| @@ -6,8 +6,7 @@ remarks: *content | |||||
| The attribute can be applied to a public settable property inside a | The attribute can be applied to a public settable property inside a | ||||
| @Discord.Commands.ModuleBase based class. By applying this attribute, | @Discord.Commands.ModuleBase based class. By applying this attribute, | ||||
| the marked property will not be automatically injected of the | the marked property will not be automatically injected of the | ||||
| dependency. See [Dependency Injection](xref:Guides.Commands.DI) | |||||
| to learn more. | |||||
| dependency. See @Guides.Commands.DI to learn more. | |||||
| --- | --- | ||||
| uid: Discord.Commands.DontInjectAttribute | uid: Discord.Commands.DontInjectAttribute | ||||
| @@ -16,6 +16,8 @@ DI when writing your modules. | |||||
| to use in the modules. | to use in the modules. | ||||
| 3. Pass the service collection into `AddModulesAsync`. | 3. Pass the service collection into `AddModulesAsync`. | ||||
| ### Example - Setting up Injection | |||||
| [!code-csharp[IServiceProvider Setup](samples/dependency_map_setup.cs)] | [!code-csharp[IServiceProvider Setup](samples/dependency_map_setup.cs)] | ||||
| ## Usage in Modules | ## Usage in Modules | ||||
| @@ -34,8 +36,10 @@ manner. | |||||
| > If you accept `CommandService` or `IServiceProvider` as a parameter | > If you accept `CommandService` or `IServiceProvider` as a parameter | ||||
| > in your constructor or as an injectable property, these entries will | > in your constructor or as an injectable property, these entries will | ||||
| > be filled by the `CommandService` that the module is loaded from and | > be filled by the `CommandService` that the module is loaded from and | ||||
| > the `ServiceProvider` that is passed into it respectively. | |||||
| > the `IServiceProvider` that is passed into it respectively. | |||||
| ### Example - Injection in Modules | |||||
| [!code-csharp[ServiceProvider in Modules](samples/dependency_module.cs)] | |||||
| [!code-csharp[IServiceProvider in Modules](samples/dependency_module.cs)] | |||||
| [DontInjectAttribute]: xref:Discord.Commands.DontInjectAttribute | [DontInjectAttribute]: xref:Discord.Commands.DontInjectAttribute | ||||
| @@ -99,19 +99,20 @@ For example: | |||||
| * ...etc. | * ...etc. | ||||
| Starting from 1.0, a command can accept nearly any type of argument; | 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 the | |||||
| below section on [Type Readers](#type-readers). | |||||
| a full list of types that are parsed by default can | |||||
| be found in @Guides.Commands.TypeReaders. | |||||
| [CommandAttribute]: xref:Discord.Commands.CommandAttribute | [CommandAttribute]: xref:Discord.Commands.CommandAttribute | ||||
| #### Optional Parameters | #### Optional Parameters | ||||
| Parameters, by default, are always required. To make a parameter | Parameters, by default, are always required. To make a parameter | ||||
| optional, give it a default value (i.e. `int num = 0`). To accept a comma-separated list, | |||||
| set the parameter to `params Type[]`. | |||||
| optional, give it a default value (i.e. `int num = 0`). | |||||
| #### Parameters with Spaces | #### Parameters with Spaces | ||||
| To accept a comma-separated list, set the parameter to `params Type[]`. | |||||
| Should a parameter include spaces, the parameter **must** be | Should a parameter include spaces, the parameter **must** be | ||||
| wrapped in quotes. For example, for a command with a parameter | wrapped in quotes. For example, for a command with a parameter | ||||
| `string food`, you would execute it with | `string food`, you would execute it with | ||||
| @@ -198,7 +199,8 @@ that are placed in the Module's constructor must be injected into an | |||||
| ### Module Properties | ### Module Properties | ||||
| Modules with `public` settable properties will have the dependencies | Modules with `public` settable properties will have the dependencies | ||||
| injected after the construction of the Module. | |||||
| injected after the construction of the module. See @Guides.Commands.DI | |||||
| to learn more. | |||||
| ### Module Groups | ### Module Groups | ||||
| @@ -216,112 +218,4 @@ Submodules are "modules" that reside within another one. Typically, | |||||
| submodules are used to create nested groups (although not required to | submodules are used to create nested groups (although not required to | ||||
| create nested groups). | create nested groups). | ||||
| [!code-csharp[Groups and Submodules](samples/groups.cs)] | |||||
| # Preconditions | |||||
| Precondition 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. | |||||
| > [!NOTE] | |||||
| > There are two types of Preconditions. | |||||
| > [PreconditionAttribute] can be applied to Modules, Groups, or Commands; | |||||
| > [ParameterPreconditionAttribute] can be applied to Parameters. | |||||
| [PreconditionAttribute]: xref:Discord.Commands.PreconditionAttribute | |||||
| [ParameterPreconditionAttribute]: xref:Discord.Commands.ParameterPreconditionAttribute | |||||
| ## Bundled Preconditions | |||||
| commands ship with four bundled Preconditions; you may view their | |||||
| usages on their respective API pages. | |||||
| * @Discord.Commands.RequireContextAttribute | |||||
| * @Discord.Commands.RequireOwnerAttribute | |||||
| * @Discord.Commands.RequireBotPermissionAttribute | |||||
| * @Discord.Commands.RequireUserPermissionAttribute | |||||
| * @Discord.Commands.RequireNsfwAttribute | |||||
| ## 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. | |||||
| Your IDE should provide an option to fill this in for you. | |||||
| If the context meets the required parameters, return | |||||
| [PreconditionResult.FromSuccess], otherwise return | |||||
| [PreconditionResult.FromError] and include an error message if | |||||
| necessary. | |||||
| [!code-csharp[Custom Precondition](samples/require_owner.cs)] | |||||
| [CheckPermissionsAsync]: xref:Discord.Commands.PreconditionAttribute.CheckPermissionsAsync* | |||||
| [PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult.FromSuccess* | |||||
| [PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult.FromError* | |||||
| # Type Readers | |||||
| Type Readers allow you to parse different types of arguments in | |||||
| your commands. | |||||
| By default, the following Types are supported arguments: | |||||
| * `bool` | |||||
| * `char` | |||||
| * `sbyte`/`byte` | |||||
| * `ushort`/`short` | |||||
| * `uint`/`int` | |||||
| * `ulong`/`long` | |||||
| * `float`, `double`, `decimal` | |||||
| * `string` | |||||
| * `DateTime`/`DateTimeOffset`/`TimeSpan` | |||||
| * `Nullable<T>` where applicible | |||||
| * Any implementation of `IChannel`/`IMessage`/`IUser`/`IRole` | |||||
| ## Creating a Type Readers | |||||
| To create a `TypeReader`, create a new class that imports @Discord and | |||||
| @Discord.Commands and ensure the class inherits from | |||||
| @Discord.Commands.TypeReader. | |||||
| Next, satisfy the `TypeReader` class by overriding the [ReadAsync] method. | |||||
| > [!NOTE] | |||||
| > In many cases, Visual Studio can fill this in for you, using the | |||||
| > "Implement Abstract Class" IntelliSense hint. | |||||
| Inside this Task, add whatever logic you need to parse the input | |||||
| string. | |||||
| If you are able to successfully parse the input, return | |||||
| [TypeReaderResult.FromSuccess] with the parsed input, otherwise return | |||||
| [TypeReaderResult.FromError] and include an error message if | |||||
| necessary. | |||||
| [TypeReaderResult]: xref:Discord.Commands.TypeReaderResult | |||||
| [TypeReaderResult.FromSuccess]: xref:Discord.Commands.TypeReaderResult.FromSuccess* | |||||
| [TypeReaderResult.FromError]: xref:Discord.Commands.TypeReaderResult.FromError* | |||||
| [ReadAsync]: xref:Discord.Commands.TypeReader.ReadAsync* | |||||
| ## Registering TypeReaders | |||||
| TypeReaders are not automatically discovered by the Command Service | |||||
| and must be explicitly added. | |||||
| To register a TypeReader, invoke [CommandService.AddTypeReader]. | |||||
| > [!WARNING] | |||||
| > TypeReaders must be added prior to module discovery, otherwise your | |||||
| > TypeReaders may not work! | |||||
| [CommandService.AddTypeReader]: xref:Discord.Commands.CommandService.AddTypeReader* | |||||
| ### Sample | |||||
| [!code-csharp[TypeReaders](samples/typereader.cs)] | |||||
| [!code-csharp[Groups and Submodules](samples/groups.cs)] | |||||
| @@ -0,0 +1,53 @@ | |||||
| --- | |||||
| uid: Guides.Commands.Preconditions | |||||
| title: Preconditions | |||||
| --- | |||||
| # Preconditions | |||||
| Precondition 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 ship with several bundled Preconditions; you may | |||||
| view their usages on their respective API pages. | |||||
| * @Discord.Commands.RequireContextAttribute | |||||
| * @Discord.Commands.RequireOwnerAttribute | |||||
| * @Discord.Commands.RequireBotPermissionAttribute | |||||
| * @Discord.Commands.RequireUserPermissionAttribute | |||||
| * @Discord.Commands.RequireNsfwAttribute | |||||
| ## 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. | |||||
| Your IDE should provide an option to fill this in for you. | |||||
| If the context meets the required parameters, return | |||||
| [PreconditionResult.FromSuccess], otherwise return | |||||
| [PreconditionResult.FromError] and include an error message if | |||||
| necessary. | |||||
| [!code-csharp[Custom Precondition](samples/require_owner.cs)] | |||||
| [CheckPermissionsAsync]: xref:Discord.Commands.PreconditionAttribute.CheckPermissionsAsync* | |||||
| [PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult.FromSuccess* | |||||
| [PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult.FromError* | |||||
| @@ -1,40 +1,30 @@ | |||||
| using Discord; | |||||
| using Discord.Commands; | |||||
| using Discord.WebSocket; | |||||
| public class ModuleA : ModuleBase<SocketCommandContext> | |||||
| public class DatabaseModule : ModuleBase<SocketCommandContext> | |||||
| { | { | ||||
| private readonly DatabaseService _database; | private readonly DatabaseService _database; | ||||
| // Dependencies can be injected via the constructor | // Dependencies can be injected via the constructor | ||||
| public ModuleA(DatabaseService database) | |||||
| public DatabaseModule(DatabaseService database) | |||||
| { | { | ||||
| _database = database; | _database = database; | ||||
| } | } | ||||
| public async Task ReadFromDb() | |||||
| [Command("read")] | |||||
| public async Task ReadFromDbAsync() | |||||
| { | { | ||||
| var x = _database.getX(); | |||||
| await ReplyAsync(x); | |||||
| await ReplyAsync(_database.GetData()); | |||||
| } | } | ||||
| } | } | ||||
| public class ModuleB : ModuleBase<SocketCommandContext> | |||||
| public class MixModule : ModuleBase<SocketCommandContext> | |||||
| { | { | ||||
| // Public settable properties will be injected. | |||||
| public AnnounceService Announce { get; set; } | |||||
| // Public settable properties will be injected | |||||
| public AnnounceService AnnounceService { get; set; } | |||||
| // Public properties without setters will not be injected. | |||||
| public CommandService Commands { get; } | |||||
| // Public properties without setters will not be injected | |||||
| public ImageService ImageService { get; } | |||||
| // Public properties annotated with [DontInject] will not | // Public properties annotated with [DontInject] will not | ||||
| // be injected. | |||||
| // be injected | |||||
| [DontInject] | [DontInject] | ||||
| public NotificationService NotificationService { get; set; } | public NotificationService NotificationService { get; set; } | ||||
| public ModuleB(CommandService commands) | |||||
| { | |||||
| Commands = commands; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,5 +1,7 @@ | |||||
| using Discord.Commands; | 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> | public class InfoModule : ModuleBase<SocketCommandContext> | ||||
| { | { | ||||
| @@ -0,0 +1,29 @@ | |||||
| public class CommandHandler | |||||
| { | |||||
| private readonly CommandService _commands; | |||||
| private readonly DiscordSocketClient _client; | |||||
| private readonly IServiceProvider _services; | |||||
| public CommandHandler(CommandService commands, DiscordSocketClient client, IServiceProvider services) | |||||
| { | |||||
| _commands = commands; | |||||
| _client = client; | |||||
| _services = services; | |||||
| } | |||||
| public async Task SetupAsync() | |||||
| { | |||||
| _client.MessageReceived += CommandHandleAsync; | |||||
| // Add BooleanTypeReader to type read for the type "bool" | |||||
| _commands.AddTypeReader(typeof(bool), new BooleanTypeReader()); | |||||
| // Then register the modules | |||||
| await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services); | |||||
| } | |||||
| public async Task CommandHandleAsync(SocketMessage msg) | |||||
| { | |||||
| // ... | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,69 @@ | |||||
| --- | |||||
| uid: Guides.Commands.TypeReaders | |||||
| title: Type Readers | |||||
| --- | |||||
| # Type Readers | |||||
| Type Readers allow you to parse different types of arguments in | |||||
| your commands. | |||||
| By default, the following Types are supported arguments: | |||||
| * `bool` | |||||
| * `char` | |||||
| * `sbyte`/`byte` | |||||
| * `ushort`/`short` | |||||
| * `uint`/`int` | |||||
| * `ulong`/`long` | |||||
| * `float`, `double`, `decimal` | |||||
| * `string` | |||||
| * `DateTime`/`DateTimeOffset`/`TimeSpan` | |||||
| * `Nullable<T>` where applicible | |||||
| * Any implementation of `IChannel`/`IMessage`/`IUser`/`IRole` | |||||
| ## Creating a Type Reader | |||||
| To create a `TypeReader`, create a new class that imports @Discord and | |||||
| @Discord.Commands and ensure the class inherits from | |||||
| @Discord.Commands.TypeReader. Next, satisfy the `TypeReader` class by | |||||
| overriding the [ReadAsync] method. | |||||
| Inside this Task, add whatever logic you need to parse the input | |||||
| string. | |||||
| If you are able to successfully parse the input, return | |||||
| [TypeReaderResult.FromSuccess] with the parsed input, otherwise return | |||||
| [TypeReaderResult.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. | |||||
| [TypeReaderResult]: xref:Discord.Commands.TypeReaderResult | |||||
| [TypeReaderResult.FromSuccess]: xref:Discord.Commands.TypeReaderResult.FromSuccess* | |||||
| [TypeReaderResult.FromError]: xref:Discord.Commands.TypeReaderResult.FromError* | |||||
| [ReadAsync]: xref:Discord.Commands.TypeReader.ReadAsync* | |||||
| ### Example - Creating a Type Reader | |||||
| [!code-csharp[TypeReaders](samples/typereader.cs)] | |||||
| ## Registering a Type Reader | |||||
| TypeReaders are not automatically discovered by the Command Service | |||||
| and must be explicitly added. | |||||
| To register a TypeReader, invoke [CommandService.AddTypeReader]. | |||||
| > [!IMPORTANT] | |||||
| > TypeReaders must be added prior to module discovery, otherwise your | |||||
| > TypeReaders may not work! | |||||
| [CommandService.AddTypeReader]: xref:Discord.Commands.CommandService.AddTypeReader* | |||||
| ### Example - Adding a Type Reader | |||||
| [!code-csharp[Adding TypeReaders](samples/typereader-register.cs)] | |||||
| @@ -1,6 +1,6 @@ | |||||
| --- | --- | ||||
| uid: Guides.Concepts.Logging | uid: Guides.Concepts.Logging | ||||
| title: Logging | |||||
| title: Logging Events/Data | |||||
| --- | --- | ||||
| # Logging in Discord.Net | # Logging in Discord.Net | ||||
| @@ -5,14 +5,15 @@ title: Start making a bot | |||||
| # Making a Ping-Pong bot | # Making a Ping-Pong bot | ||||
| One of the first steps to getting started with the Discord API is to | |||||
| write a basic ping-pong bot. We will expand on this to create more | |||||
| diverse commands later, but for now, it is a good starting point. | |||||
| One of ways to get started with the Discord API is to write a basic | |||||
| ping-pong bot. This bot will respond to a simple command "ping." | |||||
| We will expand on this to create more diverse commands later, but for | |||||
| now, it is a good starting point. | |||||
| ## Creating a Discord Bot | ## Creating a Discord Bot | ||||
| Before you can begin writing your bot, it is necessary to create a bot | |||||
| account on Discord. | |||||
| Before writing your bot, it is necessary to create a bot account via the | |||||
| Discord Applications Portal first. | |||||
| 1. Visit the [Discord Applications Portal]. | 1. Visit the [Discord Applications Portal]. | ||||
| 2. Create a New Application. | 2. Create a New Application. | ||||
| @@ -37,12 +38,14 @@ Bots **cannot** use invite links; they must be explicitly invited | |||||
| through the OAuth2 flow. | through the OAuth2 flow. | ||||
| 1. Open your bot's application on the [Discord Applications Portal]. | 1. Open your bot's application on the [Discord Applications Portal]. | ||||
| 2. Retrieve the app's **Client ID**. | |||||
| 2. Retrieve the application's **Client ID**. | |||||
|  |  | ||||
| 3. Create an OAuth2 authorization URL | 3. Create an OAuth2 authorization URL | ||||
| `https://discordapp.com/oauth2/authorize?client_id=<CLIENT ID>&scope=bot` | |||||
| - `https://discordapp.com/oauth2/authorize?client_id=<CLIENT ID>&scope=bot` | |||||
| 4. Open the authorization URL in your browser. | 4. Open the authorization URL in your browser. | ||||
| 5. Select a server. | 5. Select a server. | ||||
| 6. Click on authorize. | 6. Click on authorize. | ||||
| @@ -56,36 +59,38 @@ through the OAuth2 flow. | |||||
| ## Connecting to Discord | ## Connecting to Discord | ||||
| If you have not already created a project and installed Discord.Net, | If you have not already created a project and installed Discord.Net, | ||||
| do that now. (see the [Installing](xref:Guides.GettingStarted.Installation) section) | |||||
| do that now. | |||||
| For more information, see @Guides.GettingStarted.Installation. | |||||
| ### Async | ### Async | ||||
| Discord.Net uses .NET's [Task-based Asynchronous Pattern (TAP)] | Discord.Net uses .NET's [Task-based Asynchronous Pattern (TAP)] | ||||
| extensively - nearly every operation is asynchronous. | |||||
| extensively - nearly every operation is asynchronous. It is highly | |||||
| recommended that these operations are awaited in a | |||||
| properly established async context whenever possible. | |||||
| It is highly recommended that these operations are awaited in a | |||||
| properly established async context whenever possible. Establishing an | |||||
| async context can be problematic, but not hard. | |||||
| To establish an async context, we will be creating an async main method | |||||
| in your console application, and rewriting the static main method to | |||||
| invoke the new async main. | |||||
| To do so, we will be creating an async main in your console | |||||
| application, and rewriting the static main method to invoke the new | |||||
| async main. | |||||
| [!code-csharp[Async Context](samples/intro/async-context.cs)] | |||||
| [!code-csharp[Async Context](samples/first-bot/async-context.cs)] | |||||
| As a result of this, your program will now start and immediately | As a result of this, your program will now start and immediately | ||||
| jump into an async context. This will allow us to create a connection | jump into an async context. This will allow us to create a connection | ||||
| to Discord later on without needing to worry about setting up the | |||||
| to Discord later on without having to worry about setting up the | |||||
| correct async implementation. | correct async implementation. | ||||
| > [!TIP] | |||||
| > [!WARNING] | |||||
| > If your application throws any exceptions within an async context, | > If your application throws any exceptions within an async context, | ||||
| > they will be thrown all the way back up to the first non-async method; | > they will be thrown all the way back up to the first non-async method; | ||||
| > since our first non-async method is the program's `Main` method, this | > since our first non-async method is the program's `Main` method, this | ||||
| > means that **all** unhandled exceptions will be thrown up there, which | > means that **all** unhandled exceptions will be thrown up there, which | ||||
| > will crash your application. Discord.Net will prevent exceptions in | |||||
| > event handlers from crashing your program, but any exceptions in your | |||||
| > async main **will** cause the application to crash. | |||||
| > will crash your application. | |||||
| > | |||||
| > Discord.Net will prevent exceptions in event handlers from crashing | |||||
| > your program, but any exceptions in your async main **will** cause | |||||
| > the application to crash. | |||||
| [Task-based Asynchronous Pattern (TAP)]: https://docs.microsoft.com/en-us/dotnet/articles/csharp/async | [Task-based Asynchronous Pattern (TAP)]: https://docs.microsoft.com/en-us/dotnet/articles/csharp/async | ||||
| @@ -100,57 +105,61 @@ parameter. See the [API Documentation] for this event. | |||||
| If you are using your own logging framework, this is where you would | If you are using your own logging framework, this is where you would | ||||
| invoke it. For the sake of simplicity, we will only be logging to | invoke it. For the sake of simplicity, we will only be logging to | ||||
| the Console. | |||||
| the console. | |||||
| You may learn more about this concept in @Guides.Concepts.Logging. | |||||
| [!code-csharp[Async Context](samples/intro/logging.cs)] | |||||
| [!code-csharp[Async Context](samples/first-bot/logging.cs)] | |||||
| [API Documentation]: xref:Discord.Rest.BaseDiscordClient.Log | [API Documentation]: xref:Discord.Rest.BaseDiscordClient.Log | ||||
| ### Creating a Discord Client | ### Creating a Discord Client | ||||
| Finally, we can create a connection to Discord. Since we are writing | |||||
| a bot, we will be using a [DiscordSocketClient] along with socket | |||||
| entities. See the [terminology](xref:Guides.GettingStarted.Terminology) if you're unsure of | |||||
| the differences. | |||||
| Finally, we can create a new connection to Discord. | |||||
| Since we are writing a bot, we will be using a [DiscordSocketClient] | |||||
| along with socket entities. See @Guides.GettingStarted.Terminology | |||||
| if you are unsure of the differences. | |||||
| To do so, create an instance of [DiscordSocketClient] in your async | |||||
| main, passing in a configuration object only if necessary. For most | |||||
| To establish a new connection, we will create an instance of | |||||
| [DiscordSocketClient] in the new async main. You may pass in an | |||||
| optional @Discord.WebSocket.DiscordSocketConfig if necessary. For most | |||||
| users, the default will work fine. | users, the default will work fine. | ||||
| Before connecting, we should hook the client's `Log` event to the | Before connecting, we should hook the client's `Log` event to the | ||||
| log handler that was just created. Events in Discord.Net work | |||||
| similarly to other events in C#, so hook this event the way that | |||||
| you typically would. | |||||
| log handler that we had just created. Events in Discord.Net work | |||||
| similarly to any other events in C#. | |||||
| Next, you will need to "login to Discord" with the `LoginAsync` | |||||
| method. | |||||
| Next, you will need to "login to Discord" with the [LoginAsync] | |||||
| method with the application's "token." | |||||
| You may create a variable to hold your bot's token (this can be found | |||||
| on your bot's application page on the [Discord Applications Portal]). | |||||
| > [!NOTE] | |||||
| > Pay attention to what you are copying from the developer portal! | |||||
| > A token is not the same as the application's "client secret." | |||||
|  |  | ||||
| > [!IMPORTANT] | > [!IMPORTANT] | ||||
| > Your bot's token can be used to gain total access to your bot, so | > Your bot's token can be used to gain total access to your bot, so | ||||
| > **do __NOT__ share this token with anyone else!** It may behoove you | > **do __NOT__ share this token with anyone else!** It may behoove you | ||||
| > to store this token in an external file if you plan on distributing | |||||
| > to store this token in an external source if you plan on distributing | |||||
| > the source code for your bot. | > the source code for your bot. | ||||
| We may now invoke the client's `StartAsync` method, which will | |||||
| We may now invoke the client's [StartAsync] method, which will | |||||
| start connection/reconnection logic. It is important to note that | start connection/reconnection logic. It is important to note that | ||||
| **this method returns as soon as connection logic has been started!** | |||||
| **this method will return as soon as connection logic has been started!** | |||||
| Any methods that rely on the client's state should go in an event | Any methods that rely on the client's state should go in an event | ||||
| handler. | |||||
| handler. This means that you should **not** directly be interacting with | |||||
| the client before it is fully ready. | |||||
| Finally, we will want to block the async main method from returning | Finally, we will want to block the async main method from returning | ||||
| until after the application is exited. To do this, we can await an | |||||
| infinite delay or any other blocking method, such as reading from | |||||
| the console. | |||||
| when running the application. To do this, we can await an infinite delay | |||||
| or any other blocking method, such as reading from the console. | |||||
| The following lines can now be added: | The following lines can now be added: | ||||
| [!code-csharp[Create client](samples/intro/client.cs)] | |||||
| [!code-csharp[Create client](samples/first-bot/client.cs)] | |||||
| At this point, feel free to start your program and see your bot come | At this point, feel free to start your program and see your bot come | ||||
| online in Discord. | online in Discord. | ||||
| @@ -162,6 +171,8 @@ online in Discord. | |||||
| > for how to fix this. | > for how to fix this. | ||||
| [DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient | [DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient | ||||
| [LoginAsync]: xref:Discord.Rest.BaseDiscordClient.LoginAsync* | |||||
| [StartAsync]: xref:Discord.WebSocket.DiscordSocketClient.StartAsync* | |||||
| [installation guide]: xref:Guides.GettingStarted.Installation#installing-on-net-standard-11 | [installation guide]: xref:Guides.GettingStarted.Installation#installing-on-net-standard-11 | ||||
| ### Handling a 'ping' | ### Handling a 'ping' | ||||
| @@ -169,18 +180,18 @@ online in Discord. | |||||
| > [!WARNING] | > [!WARNING] | ||||
| > Please note that this is *not* a proper way to create a command. | > Please note that this is *not* a proper way to create a command. | ||||
| > Use the `CommandService` provided by the library instead, as explained | > Use the `CommandService` provided by the library instead, as explained | ||||
| > in the [Command Guide] section. | |||||
| > in the [Command Guide](xref:Guides.Commands.Intro) section. | |||||
| Now that we have learned how to open a connection to Discord, we can | |||||
| begin handling messages that users are sending. To start out, our bot | |||||
| will listen for any message where the content is equal to `!ping` and | |||||
| respond back with "Pong!". | |||||
| Now that we have learned to open a connection to Discord, we can | |||||
| begin handling messages that the users are sending. To start out, our | |||||
| bot will listen for any message whose content is equal to `!ping` and | |||||
| will respond back with "Pong!". | |||||
| Since we want to listen for new messages, the event to hook into | Since we want to listen for new messages, the event to hook into | ||||
| is [MessageReceived]. | is [MessageReceived]. | ||||
| In your program, add a method that matches the signature of the | In your program, add a method that matches the signature of the | ||||
| `MessageReceived` event - it must be a method (`Func`) that returns | |||||
| `MessageReceived` event - it must be a method (`Func`) that returns | |||||
| the type `Task` and takes a single parameter, a [SocketMessage]. Also, | the type `Task` and takes a single parameter, a [SocketMessage]. Also, | ||||
| since we will be sending data to Discord in this method, we will flag | since we will be sending data to Discord in this method, we will flag | ||||
| it as `async`. | it as `async`. | ||||
| @@ -189,45 +200,49 @@ In this method, we will add an `if` block to determine if the message | |||||
| content fits the rules of our scenario - recall that it must be equal | content fits the rules of our scenario - recall that it must be equal | ||||
| to `!ping`. | to `!ping`. | ||||
| Inside the branch of this condition, we will want to send a message | |||||
| back to the channel from which the message comes from - "Pong!". To | |||||
| find the channel, look for the `Channel` property on the message | |||||
| Inside the branch of this condition, we will want to send a message, | |||||
| `Pong!`, back to the channel from which the message comes from. To | |||||
| find the channel, look for the `Channel` property on the message | |||||
| parameter. | parameter. | ||||
| Next, we will want to send a message to this channel. Since the | Next, we will want to send a message to this channel. Since the | ||||
| channel object is of type [SocketMessageChannel], we can invoke the | |||||
| `SendMessageAsync` instance method. For the message content, send back | |||||
| a string containing "Pong!". | |||||
| channel object is of type [ISocketMessageChannel], we can invoke the | |||||
| [SendMessageAsync] instance method. For the message content, send back | |||||
| a string, "Pong!". | |||||
| You should have now added the following lines, | You should have now added the following lines, | ||||
| [!code-csharp[Message](samples/intro/message.cs)] | |||||
| [!code-csharp[Message](samples/first-bot/message.cs)] | |||||
| Now your first bot is complete. You may continue to add on to this | |||||
| Now that your first bot is complete. You may continue to add on to this | |||||
| if you desire, but for any bots that will be carrying out multiple | if you desire, but for any bots that will be carrying out multiple | ||||
| commands, it is strongly recommended to use the command framework as | commands, it is strongly recommended to use the command framework as | ||||
| shown below. | shown below. | ||||
| For your reference, you may view the [completed program]. | |||||
| > [!NOTE] | |||||
| > For your reference, you may view the [completed program]. | |||||
| [MessageReceived]: xref:Discord.WebSocket.BaseSocketClient.MessageReceived | [MessageReceived]: xref:Discord.WebSocket.BaseSocketClient.MessageReceived | ||||
| [SocketMessage]: xref:Discord.WebSocket.SocketMessage | [SocketMessage]: xref:Discord.WebSocket.SocketMessage | ||||
| [SocketMessageChannel]: xref:Discord.WebSocket.ISocketMessageChannel | [SocketMessageChannel]: xref:Discord.WebSocket.ISocketMessageChannel | ||||
| [completed program]: samples/intro/complete.cs | |||||
| [Command Guide]: xref:Guides.Commands.Intro | |||||
| [SendMessageAsync]: xref:Discord.WebSocket.ISocketMessageChannel.SendMessageAsync* | |||||
| [completed program]: samples/first-bot/complete.cs | |||||
| # Building a bot with commands | # Building a bot with commands | ||||
| This section will show you how to write a program that is ready for | |||||
| [Commands](xref:Guides.Commands.Intro). Note that we will not be | |||||
| explaining _how_ to write Commands or Services, it will only be | |||||
| covering the general structure. | |||||
| @Guides.Commands.Intro will guide you through how to setup a program | |||||
| that is ready for [CommandService], a service that is ready for | |||||
| advanced command usage. | |||||
| For reference, view an [annotated example] of this structure. | For reference, view an [annotated example] of this structure. | ||||
| [annotated example]: samples/intro/structure.cs | |||||
| [annotated example]: samples/first-bot/structure.cs | |||||
| It is important to know that the recommended design pattern of bots | It is important to know that the recommended design pattern of bots | ||||
| should be to separate the program (initialization and command handler), | |||||
| the modules (handle commands), and the services (persistent storage, | |||||
| pure functions, data manipulation). | |||||
| should be to separate... | |||||
| 1. the program (initialization and command handler) | |||||
| 2. the modules (handle commands) | |||||
| 3. the services (persistent storage, pure functions, data manipulation) | |||||
| [CommandService]: xref:Discord.Commands.CommandService | |||||
| @@ -3,19 +3,22 @@ uid: Guides.GettingStarted.Installation | |||||
| title: Installing Discord.Net | title: Installing Discord.Net | ||||
| --- | --- | ||||
| Discord.Net is distributed through the NuGet package manager, and it | |||||
| is recommended to use NuGet to get started. | |||||
| # Discord.Net Installation | |||||
| Optionally, you may compile from source and install yourself. | |||||
| Discord.Net is distributed through the NuGet package manager, so it is | |||||
| recommended for you to install the library that way. | |||||
| # Supported Platforms | |||||
| Alternatively, you may compile from the source and install the library | |||||
| yourself. | |||||
| ## Supported Platforms | |||||
| Currently, Discord.Net targets [.NET Standard] 1.3 and offers support | Currently, Discord.Net targets [.NET Standard] 1.3 and offers support | ||||
| for .NET Standard 1.1. If your application will be targeting .NET | for .NET Standard 1.1. If your application will be targeting .NET | ||||
| Standard 1.1, please see the [additional steps]. | Standard 1.1, please see the [additional steps]. | ||||
| Since Discord.Net is built on the .NET Standard, it is also | |||||
| recommended to create applications using [.NET Core], though not | |||||
| Since Discord.Net is built on top of .NET Standard, it is also | |||||
| recommended to create applications using [.NET Core], although it is not | |||||
| required. When using .NET Framework, it is suggested to target | required. When using .NET Framework, it is suggested to target | ||||
| `.NET Framework 4.6.1` or higher. | `.NET Framework 4.6.1` or higher. | ||||
| @@ -23,13 +26,13 @@ required. When using .NET Framework, it is suggested to target | |||||
| [.NET Core]: https://docs.microsoft.com/en-us/dotnet/articles/core/ | [.NET Core]: https://docs.microsoft.com/en-us/dotnet/articles/core/ | ||||
| [additional steps]: #installing-on-net-standard-11 | [additional steps]: #installing-on-net-standard-11 | ||||
| # Installing with NuGet | |||||
| ## Installing with NuGet | |||||
| Release builds of Discord.Net will be published to the | Release builds of Discord.Net will be published to the | ||||
| [official NuGet feed]. | [official NuGet feed]. | ||||
| Development builds of Discord.Net, as well as add-ons are published to | |||||
| our development [MyGet feed]. | |||||
| Development builds of Discord.Net, as well as add-ons, will be | |||||
| published to our [MyGet feed]. | |||||
| Direct feed link: `https://www.myget.org/F/discord-net/api/v3/index.json` | Direct feed link: `https://www.myget.org/F/discord-net/api/v3/index.json` | ||||
| @@ -41,7 +44,7 @@ Not sure how to add a direct feed? See how [with Visual Studio] or | |||||
| [with Visual Studio]: https://docs.microsoft.com/en-us/nuget/tools/package-manager-ui#package-sources | [with Visual Studio]: https://docs.microsoft.com/en-us/nuget/tools/package-manager-ui#package-sources | ||||
| [without Visual Studio]: #configuring-nuget-without-visual-studio | [without Visual Studio]: #configuring-nuget-without-visual-studio | ||||
| ## [Using Visual Studio](#tab/vs-install) | |||||
| ### [Using Visual Studio](#tab/vs-install) | |||||
| > [!TIP] | > [!TIP] | ||||
| > Don't forget to change your package source if you're installing from | > Don't forget to change your package source if you're installing from | ||||
| @@ -49,8 +52,8 @@ Not sure how to add a direct feed? See how [with Visual Studio] or | |||||
| > Also make sure to check "Enable Prereleases" if installing a dev | > Also make sure to check "Enable Prereleases" if installing a dev | ||||
| > build! | > build! | ||||
| 1. Create a solution for your bot. | |||||
| 2. In Solution Explorer, find the "Dependencies" element under your | |||||
| 1. Create a new solution for your bot. | |||||
| 2. In the Solution Explorer, find the "Dependencies" element under your | |||||
| bot's project. | bot's project. | ||||
| 3. Right click on "Dependencies", and select "Manage NuGet packages." | 3. Right click on "Dependencies", and select "Manage NuGet packages." | ||||
|  |  | ||||
| @@ -58,7 +61,7 @@ Not sure how to add a direct feed? See how [with Visual Studio] or | |||||
| 5. Install the `Discord.Net` package. | 5. Install the `Discord.Net` package. | ||||
|  |  | ||||
| ## [Using JetBrains Rider](#tab/rider-install) | |||||
| ### [Using JetBrains Rider](#tab/rider-install) | |||||
| > [!TIP] | > [!TIP] | ||||
| > Make sure to check the "Prerelease" box if installing a dev build! | > Make sure to check the "Prerelease" box if installing a dev build! | ||||
| @@ -72,7 +75,7 @@ Not sure how to add a direct feed? See how [with Visual Studio] or | |||||
| 4. Install by adding the package to your project. | 4. Install by adding the package to your project. | ||||
|  |  | ||||
| ## [Using Visual Studio Code](#tab/vs-code) | |||||
| ### [Using Visual Studio Code](#tab/vs-code) | |||||
| > [!TIP] | > [!TIP] | ||||
| > Don't forget to add the package source to a [NuGet.Config file] if | > Don't forget to add the package source to a [NuGet.Config file] if | ||||
| @@ -81,11 +84,11 @@ Not sure how to add a direct feed? See how [with Visual Studio] or | |||||
| 1. Create a new project for your bot. | 1. Create a new project for your bot. | ||||
| 2. Add `Discord.Net` to your .csproj. | 2. Add `Discord.Net` to your .csproj. | ||||
| [!code[Sample .csproj](samples/project.csproj)] | |||||
| [!code[Sample .csproj](samples/project.xml)] | |||||
| [NuGet.Config file]: #configuring-nuget-without-visual-studio | [NuGet.Config file]: #configuring-nuget-without-visual-studio | ||||
| ## [Using dotnet CLI](#tab/dotnet-cli) | |||||
| ### [Using dotnet CLI](#tab/dotnet-cli) | |||||
| > [!TIP] | > [!TIP] | ||||
| > Don't forget to add the package source to a [NuGet.Config file] if | > Don't forget to add the package source to a [NuGet.Config file] if | ||||
| @@ -98,11 +101,11 @@ Not sure how to add a direct feed? See how [with Visual Studio] or | |||||
| *** | *** | ||||
| # Compiling from Source | |||||
| ## Compiling from Source | |||||
| In order to compile Discord.Net, you require the following: | |||||
| In order to compile Discord.Net, you will need the following: | |||||
| ## Using Visual Studio | |||||
| ### Using Visual Studio | |||||
| - [Visual Studio 2017](https://www.visualstudio.com/) | - [Visual Studio 2017](https://www.visualstudio.com/) | ||||
| - [.NET Core SDK] | - [.NET Core SDK] | ||||
| @@ -110,31 +113,32 @@ In order to compile Discord.Net, you require the following: | |||||
| The .NET Core and Docker (Preview) workload is required during Visual | The .NET Core and Docker (Preview) workload is required during Visual | ||||
| Studio installation. | Studio installation. | ||||
| ## Using Command Line | |||||
| ### Using Command Line | |||||
| - [.NET Core SDK] | - [.NET Core SDK] | ||||
| [.NET Core SDK]: https://www.microsoft.com/net/download/ | [.NET Core SDK]: https://www.microsoft.com/net/download/ | ||||
| # Additional Information | |||||
| ## Additional Information | |||||
| ## Installing on .NET Standard 1.1 | |||||
| ### Installing on .NET Standard 1.1 | |||||
| For applications targeting a runtime corresponding with .NET Standard | For applications targeting a runtime corresponding with .NET Standard | ||||
| 1.1 or 1.2, the builtin WebSocket and UDP provider will not work. For | |||||
| applications which utilize a WebSocket connection to Discord | |||||
| (WebSocket or RPC), third-party provider packages will need to be | |||||
| 1.1 or 1.2, the built-in WebSocket and UDP provider will not work. For | |||||
| applications which utilize a WebSocket connection to Discord, such as | |||||
| WebSocket or RPC, third-party provider packages will need to be | |||||
| installed and configured. | installed and configured. | ||||
| First, install the following packages through NuGet, or compile | |||||
| > [!NOTE] | |||||
| > `Discord.Net.Providers.UDPClient` is _only_ required if your | |||||
| > bot will be utilizing voice chat. | |||||
| First, install the following packages through NuGet, or compile them | |||||
| yourself, if you prefer: | yourself, if you prefer: | ||||
| - Discord.Net.Providers.WS4Net | - Discord.Net.Providers.WS4Net | ||||
| - Discord.Net.Providers.UDPClient | - Discord.Net.Providers.UDPClient | ||||
| Note that `Discord.Net.Providers.UDPClient` is _only_ required if your | |||||
| bot will be utilizing voice chat. | |||||
| Next, you will need to configure your [DiscordSocketClient] to use | Next, you will need to configure your [DiscordSocketClient] to use | ||||
| these custom providers over the default ones. | these custom providers over the default ones. | ||||
| @@ -147,16 +151,16 @@ are passing into your client. | |||||
| [DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient | [DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient | ||||
| [DiscordSocketConfig]: xref:Discord.WebSocket.DiscordSocketConfig | [DiscordSocketConfig]: xref:Discord.WebSocket.DiscordSocketConfig | ||||
| ## Configuring NuGet without Visual Studio | |||||
| ### Configuring NuGet without Visual Studio | |||||
| If you plan on deploying your bot or developing outside of Visual | If you plan on deploying your bot or developing outside of Visual | ||||
| Studio, you will need to create a local NuGet configuration file for | Studio, you will need to create a local NuGet configuration file for | ||||
| your project. | your project. | ||||
| To do this, create a file named `nuget.config` alongside the root of | |||||
| your application, where the project solution is located. | |||||
| To do this, create a file named `NuGet.Config` alongside the root of | |||||
| your application, where the project is located. | |||||
| Paste the following snippets into this configuration file, adding any | Paste the following snippets into this configuration file, adding any | ||||
| additional feeds as necessary. | |||||
| additional feeds if necessary. | |||||
| [!code[NuGet Configuration](samples/nuget.config)] | [!code[NuGet Configuration](samples/nuget.config)] | ||||
| @@ -0,0 +1,9 @@ | |||||
| public class Program | |||||
| { | |||||
| public static void Main(string[] args) | |||||
| => new Program().MainAsync().GetAwaiter().GetResult(); | |||||
| public async Task MainAsync() | |||||
| { | |||||
| } | |||||
| } | |||||
| @@ -1,17 +1,17 @@ | |||||
| // Program.cs | |||||
| using Discord.WebSocket; | |||||
| // ... | |||||
| private DiscordSocketClient _client; | private DiscordSocketClient _client; | ||||
| public async Task MainAsync() | public async Task MainAsync() | ||||
| { | { | ||||
| _client = new DiscordSocketClient(); | _client = new DiscordSocketClient(); | ||||
| _client.Log += Log; | _client.Log += Log; | ||||
| string token = "abcdefg..."; // Remember to keep this private! | |||||
| // Remember to keep this private or to read this | |||||
| // from an external source! | |||||
| string token = "abcdefg..."; | |||||
| await _client.LoginAsync(TokenType.Bot, token); | await _client.LoginAsync(TokenType.Bot, token); | ||||
| await _client.StartAsync(); | await _client.StartAsync(); | ||||
| // Block this task until the program is closed. | // Block this task until the program is closed. | ||||
| await Task.Delay(-1); | await Task.Delay(-1); | ||||
| } | |||||
| } | |||||
| @@ -0,0 +1,38 @@ | |||||
| public class Program | |||||
| { | |||||
| private DiscordSocketClient _client; | |||||
| public static void Main(string[] args) | |||||
| => new Program().MainAsync().GetAwaiter().GetResult(); | |||||
| public async Task MainAsync() | |||||
| { | |||||
| _client = new DiscordSocketClient(); | |||||
| _client.Log += Log; | |||||
| _client.MessageReceived += MessageReceivedAsync; | |||||
| // Remember to keep this private or to read this | |||||
| // from an external source! | |||||
| string token = "abcdefg..."; | |||||
| await _client.LoginAsync(TokenType.Bot, token); | |||||
| await _client.StartAsync(); | |||||
| // Block this task until the program is closed. | |||||
| await Task.Delay(-1); | |||||
| } | |||||
| private async Task MessageReceivedAsync(SocketMessage message) | |||||
| { | |||||
| if (message.Content == "!ping") | |||||
| { | |||||
| await message.Channel.SendMessageAsync("Pong!"); | |||||
| } | |||||
| } | |||||
| private Task Log(LogMessage msg) | |||||
| { | |||||
| Console.WriteLine(msg.ToString()); | |||||
| return Task.CompletedTask; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,5 @@ | |||||
| private Task Log(LogMessage msg) | |||||
| { | |||||
| Console.WriteLine(msg.ToString()); | |||||
| return Task.CompletedTask; | |||||
| } | |||||
| @@ -1,6 +1,6 @@ | |||||
| public async Task MainAsync() | public async Task MainAsync() | ||||
| { | { | ||||
| // client.Log ... | |||||
| // ... | |||||
| _client.MessageReceived += MessageReceived; | _client.MessageReceived += MessageReceived; | ||||
| // ... | // ... | ||||
| } | } | ||||
| @@ -1,15 +0,0 @@ | |||||
| using System; | |||||
| using System.Threading.Tasks; | |||||
| namespace MyBot | |||||
| { | |||||
| public class Program | |||||
| { | |||||
| public static void Main(string[] args) | |||||
| => new Program().MainAsync().GetAwaiter().GetResult(); | |||||
| public async Task MainAsync() | |||||
| { | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,44 +0,0 @@ | |||||
| using Discord; | |||||
| using Discord.WebSocket; | |||||
| using System; | |||||
| using System.Threading.Tasks; | |||||
| namespace MyBot | |||||
| { | |||||
| public class Program | |||||
| { | |||||
| private DiscordSocketClient _client; | |||||
| public static void Main(string[] args) | |||||
| => new Program().MainAsync().GetAwaiter().GetResult(); | |||||
| public async Task MainAsync() | |||||
| { | |||||
| _client = new DiscordSocketClient(); | |||||
| _client.Log += Log; | |||||
| _client.MessageReceived += MessageReceived; | |||||
| string token = "abcdefg..."; // Remember to keep this private! | |||||
| await _client.LoginAsync(TokenType.Bot, token); | |||||
| await _client.StartAsync(); | |||||
| // Block this task until the program is closed. | |||||
| await Task.Delay(-1); | |||||
| } | |||||
| private async Task MessageReceived(SocketMessage message) | |||||
| { | |||||
| if (message.Content == "!ping") | |||||
| { | |||||
| await message.Channel.SendMessageAsync("Pong!"); | |||||
| } | |||||
| } | |||||
| private Task Log(LogMessage msg) | |||||
| { | |||||
| Console.WriteLine(msg.ToString()); | |||||
| return Task.CompletedTask; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,22 +0,0 @@ | |||||
| using Discord; | |||||
| using System; | |||||
| using System.Threading.Tasks; | |||||
| namespace MyBot | |||||
| { | |||||
| public class Program | |||||
| { | |||||
| public static void Main(string[] args) | |||||
| => new Program().MainAsync().GetAwaiter().GetResult(); | |||||
| public async Task MainAsync() | |||||
| { | |||||
| } | |||||
| private Task Log(LogMessage msg) | |||||
| { | |||||
| Console.WriteLine(msg.ToString()); | |||||
| return Task.CompletedTask; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,4 +1,5 @@ | |||||
| <Project Sdk="Microsoft.NET.Sdk"> | <Project Sdk="Microsoft.NET.Sdk"> | ||||
| <!-- | <!-- | ||||
| The following may differ depending on the latest version of | The following may differ depending on the latest version of | ||||
| .NET Core Framework or Discord.Net. | .NET Core Framework or Discord.Net. | ||||
| @@ -26,7 +26,7 @@ Here are some examples: | |||||
| > It is not meant to be something that will work out of the box. | > It is not meant to be something that will work out of the box. | ||||
| [Official template]: https://github.com/foxbot/DiscordBotBase/tree/csharp/src/DiscordBot | [Official template]: https://github.com/foxbot/DiscordBotBase/tree/csharp/src/DiscordBot | ||||
| [Official quick start guide]: https://github.com/RogueException/Discord.Net/blob/dev/docs/guides/getting_started/samples/intro/structure.cs | |||||
| [Official quick start guide]: https://github.com/RogueException/Discord.Net/blob/dev/docs/guides/getting_started/samples/first-bot/structure.cs | |||||
| [Task-based Asynchronous Pattern]: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap | [Task-based Asynchronous Pattern]: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap | ||||
| [polymorphism]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism | [polymorphism]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism | ||||
| [interface]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ | [interface]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ | ||||
| @@ -20,8 +20,12 @@ | |||||
| topicUid: Guides.Concepts.Entities | topicUid: Guides.Concepts.Entities | ||||
| - name: The Command Service | - name: The Command Service | ||||
| items: | items: | ||||
| - name: Introduction to Command Service | |||||
| - name: Introduction | |||||
| topicUid: Guides.Commands.Intro | topicUid: Guides.Commands.Intro | ||||
| - name: TypeReaders | |||||
| topicUid: Guides.Commands.TypeReaders | |||||
| - name: Preconditions | |||||
| topicUid: Guides.Commands.Preconditions | |||||
| - name: Dependency Injection | - name: Dependency Injection | ||||
| topicUid: Guides.Commands.DI | topicUid: Guides.Commands.DI | ||||
| - name: Post-execution Handling | - name: Post-execution Handling | ||||