diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index 1d9c17c21..000000000 --- a/docs/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ - -############### -# folder # -############### -/**/DROP/ -/**/TEMP/ -/**/packages/ -/**/bin/ -/**/obj/ -_site \ No newline at end of file diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index 296b6d1cb..000000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1,46 +0,0 @@ -# Contributing to Docs - -I don't really have any strict conditions for writing documentation, -but just keep these few guidelines in mind: - -* Keep code samples in the `guides/samples` folder -* When referencing an object in the API, link to it's page in the -API documentation. -* 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`). - -### Layout - -Documentation should be written in a FAQ/Wiki style format. - -Recommended reads: - -* http://docs.microsoft.com -* http://flask.pocoo.org/docs/0.12/ - -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: - -``` -Please consult the [API Documentation] for more information. - -[API Documentation]: xref:System.String -``` - -### Compiling - -Documentation is compiled into a static site using [DocFx]. -We currently use the most recent build off the dev branch. - -After making changes, compile your changes into the static site with -`docfx`. You can also view your changes live with `docfx --serve`. - -[DocFx]: https://dotnet.github.io/docfx/ \ No newline at end of file diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index a672330d4..000000000 --- a/docs/README.md +++ /dev/null @@ -1,16 +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. (Optional) If you intend to target a specific version, ensure that you -have the correct version checked out. -3. Build the library. Run `dotnet build` in the root of this repository. - Ensure that the build passes without errors. -4. Build the docs using `docfx .\docs\docfx.json`. Add the `--serve` parameter -to preview the site locally. Some elements of the page may appear incorrect -when not hosted by a server. - - Remarks: According to the docfx website, this tool does work on Linux under mono. - -[docfx-main]: https://dotnet.github.io/docfx/ -[docfx-installing]: https://dotnet.github.io/docfx/tutorial/docfx_getting_started.html diff --git a/docs/api/.gitignore b/docs/api/.gitignore deleted file mode 100644 index bffdb3075..000000000 --- a/docs/api/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ - -############### -# temp file # -############### -*.yml -.manifest \ No newline at end of file diff --git a/docs/api/index.md b/docs/api/index.md deleted file mode 100644 index d9433363f..000000000 --- a/docs/api/index.md +++ /dev/null @@ -1,13 +0,0 @@ - -# 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 \ No newline at end of file diff --git a/docs/docfx.json b/docs/docfx.json deleted file mode 100644 index 50ae39092..000000000 --- a/docs/docfx.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "metadata": [ - { - "src": [ - { - "src": "..", - "files": [ - "src/**/*.cs" - ], - "exclude": [ - "**/obj/**", - "**/bin/**", - "_site/**" - ] - } - ], - "dest": "api", - "filter": "filterConfig.yml" - } - ], - "build": { - "content": [ - { - "files": [ - "api/**.yml", - "api/index.md" - ] - }, - { - "files": [ - "guides/**.md", - "guides/**/toc.yml", - "toc.yml", - "*.md" - ], - "exclude": [ - "obj/**", - "_site/**" - ] - } - ], - "resource": [ - { - "files": [ - "**/images/**", - "**/samples/**" - ], - "exclude": [ - "obj/**", - "_site/**" - ] - } - ], - "overwrite": [ - { - "files": [ - "apidoc/**.md" - ], - "exclude": [ - "obj/**", - "_site/**" - ] - } - ], - "dest": "_site", - "template": [ - "default" - ], - "globalMetadata": { - "_appFooter": "Discord.Net (c) 2015-2018 2.0.0-beta" - }, - "noLangKeyword": false - } -} diff --git a/docs/filterConfig.yml b/docs/filterConfig.yml deleted file mode 100644 index 715b39606..000000000 --- a/docs/filterConfig.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiRules: -- exclude: - uidRegex: ^Discord\.API$ -- exclude: - uidRegex: ^Discord\.API.*$ -- exclude: - uidRegex: ^Discord\.Net\.Converters$ -- exclude: - uidRegex: ^Discord\.Net.*$ -- exclude: - uidRegex: ^RegexAnalyzer$ \ No newline at end of file diff --git a/docs/guides/commands/commands.md b/docs/guides/commands/commands.md deleted file mode 100644 index 2b012af0e..000000000 --- a/docs/guides/commands/commands.md +++ /dev/null @@ -1,343 +0,0 @@ -# The Command Service - -[Discord.Commands](xref:Discord.Commands) provides an Attribute-based -command parser. - -## Setup - -To use Commands, you must create a [Command Service] and a Command -Handler. - -Included below is a very barebone Command Handler. You can extend your -Command Handler as much as you like; however, the below is the bare -minimum. - -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/command_handler.cs)] - -[Command Service]: xref:Discord.Commands.CommandService -[CommandServiceConfig]: xref:Discord.Commands.CommandServiceConfig - -## With Attributes - -In 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 from -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. - -**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]. - -To begin, create a new class somewhere in your project and inherit the -class from [ModuleBase]. This class **must** be `public`. - ->[!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. - -By now, your module should look like this: - -[!code-csharp[Empty Module](samples/empty-module.cs)] - -[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 Commands - -The next step to creating Commands is actually creating the Commands. - -To create a Command, add a method to your module of type `Task`. -Typically, you will want to mark this method as `async`, although it -is not required. - -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 -arg`; to take a user as an argument from the user, add `IUser user`. -In 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_. - -Parameters, by default, are always required. To make a parameter -optional, give it a default value. To accept a comma-separated list, -set the parameter to `params Type[]`. - -Should a parameter include spaces, it **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. - -Finally, flag your Command with the [CommandAttribute]. (you must -specify a name for this Command, except for when it is part of a -Module Group - see below) - -[RemainderAttribute]: xref:Discord.Commands.RemainderAttribute -[CommandAttribute]: xref:Discord.Commands.CommandAttribute - -### 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, and user that the Command was invoked from, -as well as the underlying Discord client that the Command was invoked -from. - -Different types of Contexts 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#Discord_Commands_ModuleBase_1_Context -[SocketCommandContext]: xref:Discord.Commands.SocketCommandContext -[ReplyAsync]: xref:Discord.Commands.ModuleBase`1#Discord_Commands_ModuleBase_1_ReplyAsync_System_String_System_Boolean_Discord_Embed_Discord_RequestOptions_ - -### Example Module - -At this point, your module should look comparable to this example: -[!code-csharp[Example Module](samples/module.cs)] - -#### Loading Modules Automatically - -The Command Service can automatically discover all classes in an -Assembly that inherit [ModuleBase] and load them. - -To opt a module out of auto-loading, flag it with -[DontAutoLoadAttribute]. - -Invoke [CommandService.AddModulesAsync] to discover modules and -install them. - -[DontAutoLoadAttribute]: xref:Discord.Commands.DontAutoLoadAttribute -[CommandService.AddModulesAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModulesAsync_Assembly_ - -#### Loading Modules Manually - -To manually load a module, invoke [CommandService.AddModuleAsync] by -passing in the generic type of your module and optionally, a -dependency map. - -[CommandService.AddModuleAsync]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddModuleAsync__1 - -### Module Constructors - -Modules are constructed using Dependency Injection. Any parameters -that are placed in the Module's constructor must be injected into an -@System.IServiceProvider first. Alternatively, you may accept an -`IServiceProvider` as an argument and extract services yourself. - -### Module Properties - -Modules with `public` settable properties will have the dependencies -injected after the construction of the Module. - -### 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/groups.cs)] - -## With Builders - -**TODO** - -## 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 - -First, you need to create an @System.IServiceProvider; you may create -your own one if you wish. - -Next, add the dependencies that your modules will use to the map. - -Finally, pass the map into the `LoadAssembly` method. Your modules -will be automatically loaded with this dependency map. - -[!code-csharp[IServiceProvider Setup](samples/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 into `LoadAssembly`. - -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 `ServiceProvider` that is passed into it respectively. - -[!code-csharp[ServiceProvider in Modules](samples/dependency_module.cs)] - -[DontInjectAttribute]: xref:Discord.Commands.DontInjectAttribute - -# 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 - -## 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 [CheckPermissions] 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)] - -[CheckPermissions]: xref:Discord.Commands.PreconditionAttribute#Discord_Commands_PreconditionAttribute_CheckPermissions_Discord_Commands_ICommandContext_Discord_Commands_CommandInfo_IServiceProvider_ -[PreconditionResult.FromSuccess]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromSuccess -[PreconditionResult.FromError]: xref:Discord.Commands.PreconditionResult#Discord_Commands_PreconditionResult_FromError_System_String_ - -# 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 -- IMessage/IUserMessage -- IChannel/IGuildChannel/ITextChannel/IVoiceChannel/IGroupChannel -- IUser/IGuildUser/IGroupUser -- 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 [Read] 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#Discord_Commands_TypeReaderResult_FromSuccess_Discord_Commands_TypeReaderValue_ -[TypeReaderResult.FromError]: xref:Discord.Commands.TypeReaderResult#Discord_Commands_TypeReaderResult_FromError_Discord_Commands_CommandError_System_String_ -[Read]: xref:Discord.Commands.TypeReader#Discord_Commands_TypeReader_Read_Discord_Commands_ICommandContext_System_String_IServiceProvider_ - -#### Sample - -[!code-csharp[TypeReaders](samples/typereader.cs)] - -### Installing TypeReaders - -TypeReaders are not automatically discovered by the Command Service -and must be explicitly added. - -To install a TypeReader, invoke [CommandService.AddTypeReader]. - -[CommandService.AddTypeReader]: xref:Discord.Commands.CommandService#Discord_Commands_CommandService_AddTypeReader__1_Discord_Commands_TypeReader_ diff --git a/docs/guides/commands/samples/command_handler.cs b/docs/guides/commands/samples/command_handler.cs deleted file mode 100644 index da2453aa8..000000000 --- a/docs/guides/commands/samples/command_handler.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Reflection; -using Discord; -using Discord.WebSocket; -using Discord.Commands; -using Microsoft.Extensions.DependencyInjection; - -public class Program -{ - private CommandService _commands; - private DiscordSocketClient _client; - private IServiceProvider _services; - - private static void Main(string[] args) => new Program().StartAsync().GetAwaiter().GetResult(); - - public async Task StartAsync() - { - _client = new DiscordSocketClient(); - _commands = new CommandService(); - - // Avoid hard coding your token. Use an external source instead in your code. - string token = "bot token here"; - - _services = new ServiceCollection() - .AddSingleton(_client) - .AddSingleton(_commands) - .BuildServiceProvider(); - - await InstallCommandsAsync(); - - await _client.LoginAsync(TokenType.Bot, token); - await _client.StartAsync(); - - await Task.Delay(-1); - } - - public async Task InstallCommandsAsync() - { - // Hook the MessageReceived Event into our Command Handler - _client.MessageReceived += HandleCommandAsync; - // Discover all of the commands in this assembly and load them. - await _commands.AddModulesAsync(Assembly.GetEntryAssembly()); - } - - 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 if it starts with '!' or a mention prefix - if (!(message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(_client.CurrentUser, ref argPos))) return; - // Create a Command Context - var context = new SocketCommandContext(_client, message); - // Execute the command. (result does not indicate a return value, - // rather an object stating if the command executed successfully) - var result = await _commands.ExecuteAsync(context, argPos, _services); - if (!result.IsSuccess) - await context.Channel.SendMessageAsync(result.ErrorReason); - } -} \ No newline at end of file diff --git a/docs/guides/commands/samples/dependency_map_setup.cs b/docs/guides/commands/samples/dependency_map_setup.cs deleted file mode 100644 index a36925904..000000000 --- a/docs/guides/commands/samples/dependency_map_setup.cs +++ /dev/null @@ -1,18 +0,0 @@ -private IServiceProvider _services; -private CommandService _commands; - -public async Task InstallAsync(DiscordSocketClient client) -{ - // Here, we will inject the ServiceProvider with - // all of the services our client will use. - _services = 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. - .AddSingleton() - .BuildServiceProvider(); - // ... - await _commands.AddModulesAsync(Assembly.GetEntryAssembly()); -} \ No newline at end of file diff --git a/docs/guides/commands/samples/dependency_module.cs b/docs/guides/commands/samples/dependency_module.cs deleted file mode 100644 index 561b0f6ac..000000000 --- a/docs/guides/commands/samples/dependency_module.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Discord; -using Discord.Commands; -using Discord.WebSocket; - -public class ModuleA : ModuleBase -{ - private readonly DatabaseService _database; - - // Dependencies can be injected via the constructor - public ModuleA(DatabaseService database) - { - _database = database; - } - - public async Task ReadFromDb() - { - var x = _database.getX(); - await ReplyAsync(x); - } -} - -public class ModuleB -{ - - // Public settable properties will be injected - public AnnounceService { get; set; } - - // Public properties without setters will not - public CommandService Commands { get; } - - // Public properties annotated with [DontInject] will not - [DontInject] - public NotificationService { get; set; } - - public ModuleB(CommandService commands) - { - Commands = commands; - } - -} diff --git a/docs/guides/commands/samples/empty-module.cs b/docs/guides/commands/samples/empty-module.cs deleted file mode 100644 index 6483c7cd2..000000000 --- a/docs/guides/commands/samples/empty-module.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Discord.Commands; - -public class InfoModule : ModuleBase -{ - -} \ No newline at end of file diff --git a/docs/guides/commands/samples/groups.cs b/docs/guides/commands/samples/groups.cs deleted file mode 100644 index 5f96c34e8..000000000 --- a/docs/guides/commands/samples/groups.cs +++ /dev/null @@ -1,18 +0,0 @@ -[Group("admin")] -public class AdminModule : ModuleBase -{ - [Group("clean")] - public class CleanModule : ModuleBase - { - // ~admin clean 15 - [Command] - public async Task Default(int count = 10) => Messages(count); - - // ~admin clean messages 15 - [Command("messages")] - public async Task Messages(int count = 10) { } - } - // ~admin ban foxbot#0282 - [Command("ban")] - public async Task Ban(IGuildUser user) { } -} \ No newline at end of file diff --git a/docs/guides/commands/samples/module.cs b/docs/guides/commands/samples/module.cs deleted file mode 100644 index 1e3555501..000000000 --- a/docs/guides/commands/samples/module.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Create a module with no prefix -public class Info : ModuleBase -{ - // ~say hello -> hello - [Command("say")] - [Summary("Echoes a message.")] - public async Task SayAsync([Remainder] [Summary("The text to echo")] string echo) - { - // ReplyAsync is a method on ModuleBase - await ReplyAsync(echo); - } -} - -// Create a module with the 'sample' prefix -[Group("sample")] -public class Sample : ModuleBase -{ - // ~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 for")] SocketUser user = null) - { - var userInfo = user ?? Context.Client.CurrentUser; - await ReplyAsync($"{userInfo.Username}#{userInfo.Discriminator}"); - } -} diff --git a/docs/guides/commands/samples/require_owner.cs b/docs/guides/commands/samples/require_owner.cs deleted file mode 100644 index 3611afab8..000000000 --- a/docs/guides/commands/samples/require_owner.cs +++ /dev/null @@ -1,24 +0,0 @@ -// (Note: This precondition is obsolete, it is recommended to use the RequireOwnerAttribute that is bundled with Discord.Commands) - -using Discord.Commands; -using Discord.WebSocket; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Threading.Tasks; - -// Inherit from PreconditionAttribute -public class RequireOwnerAttribute : PreconditionAttribute -{ - // Override the CheckPermissions method - public async override Task CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services) - { - // Get the ID of the bot's owner - var ownerId = (await services.GetService().GetApplicationInfoAsync()).Owner.Id; - // If this command was executed by that user, return a success - if (context.User.Id == ownerId) - return PreconditionResult.FromSuccess(); - // Since it wasn't, fail - else - return PreconditionResult.FromError("You must be the owner of the bot to run this command."); - } -} diff --git a/docs/guides/commands/samples/typereader.cs b/docs/guides/commands/samples/typereader.cs deleted file mode 100644 index d2864a4c7..000000000 --- a/docs/guides/commands/samples/typereader.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Note: This example is obsolete, a boolean type reader is bundled with Discord.Commands -using Discord; -using Discord.Commands; - -public class BooleanTypeReader : TypeReader -{ - public override Task Read(ICommandContext context, string input, IServiceProvider services) - { - bool result; - if (bool.TryParse(input, out result)) - return Task.FromResult(TypeReaderResult.FromSuccess(result)); - - return Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, "Input could not be parsed as a boolean.")); - } -} diff --git a/docs/guides/concepts/connections.md b/docs/guides/concepts/connections.md deleted file mode 100644 index 30e5e55cd..000000000 --- a/docs/guides/concepts/connections.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Managing Connections ---- - -In Discord.Net, once a client has been started, it will automatically -maintain a connection to Discord's gateway, until it is manually -stopped. - -### Usage - -To start a connection, invoke the `StartAsync` method on a client that -supports a WebSocket connection. - -These clients include the [DiscordSocketClient] and -[DiscordRpcClient], as well as Audio clients. - -To end a connection, invoke the `StopAsync` method. This will -gracefully close any open WebSocket or UdpSocket connections. - -Since the Start/Stop methods only signal to an underlying connection -manager that a connection needs to be started, **they return before a -connection is actually made.** - -As a result, you will need to hook into one of the connection-state -based events to have an accurate representation of when a client is -ready for use. - -All clients provide a `Connected` and `Disconnected` event, which is -raised respectively when a connection opens or closes. In the case of -the DiscordSocketClient, this does **not** mean that the client is -ready to be used. - -A separate event, `Ready`, is provided on DiscordSocketClient, which -is raised only when the client has finished guild stream or guild -sync, and has a complete guild cache. - -[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient -[DiscordRpcClient]: xref:Discord.Rpc.DiscordRpcClient - -### Samples - -[!code-csharp[Connection Sample](samples/events.cs)] - -### Tips - -Avoid running long-running code on the gateway! If you deadlock the -gateway (as explained in [events]), the connection manager will be -unable to recover and reconnect. - -Assuming the client disconnected because of a fault on Discord's end, -and not a deadlock on your end, we will always attempt to reconnect -and resume a connection. - -Don't worry about trying to maintain your own connections, the -connection manager is designed to be bulletproof and never fail - if -your client doesn't manage to reconnect, you've found a bug! - -[events]: events.md \ No newline at end of file diff --git a/docs/guides/concepts/entities.md b/docs/guides/concepts/entities.md deleted file mode 100644 index 3a5d5496b..000000000 --- a/docs/guides/concepts/entities.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: Entities ---- - ->[!NOTE] -This article is written with the Socket variants of entities in mind, -not the general interfaces or Rest/Rpc entities. - -Discord.Net provides a versatile entity system for navigating the -Discord API. - -### Inheritance - -Due to the nature of the Discord API, some entities are designed with -multiple variants; for example, `SocketUser` and `SocketGuildUser`. - -All models will contain the most detailed version of an entity -possible, even if the type is less detailed. - -For example, in the case of the `MessageReceived` event, a -`SocketMessage` is passed in with a channel property of type -`SocketMessageChannel`. All messages come from channels capable of -messaging, so this is the only variant of a channel that can cover -every single case. - -But that doesn't mean a message _can't_ come from a -`SocketTextChannel`, which is a message channel in a guild. To -retrieve information about a guild from a message entity, you will -need to cast its channel object to a `SocketTextChannel`. - -### Navigation - -All socket entities have navigation properties on them, which allow -you to easily navigate to an entity's parent or children. As explained -above, you will sometimes need to cast to a more detailed version of -an entity to navigate to its parent. - -### Accessing Entities - -The most basic forms of entities, `SocketGuild`, `SocketUser`, and -`SocketChannel` can be pulled from the DiscordSocketClient's global -cache, and can be retrieved using the respective `GetXXX` method on -DiscordSocketClient. - ->[!TIP] -It is **vital** that you use the proper IDs for an entity when using -a GetXXX method. It is recommended that you enable Discord's -_developer mode_ to allow easy access to entity IDs, found in -Settings > Appearance > Advanced - -More detailed versions of entities can be pulled from the basic -entities, e.g. `SocketGuild.GetUser`, which returns a -`SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a -`SocketGuildChannel`. Again, you may need to cast these objects to get -a variant of the type that you need. - -### Samples - -[!code-csharp[Entity Sample](samples/entities.cs)] - -### Tips - -Avoid using boxing-casts to coerce entities into a variant, use the -[`as`] keyword, and a null-conditional operator instead. - -This allows you to write safer code and avoid [InvalidCastExceptions]. - -For example, `(message.Author as SocketGuildUser)?.Nickname`. - -[`as`]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as -[InvalidCastExceptions]: https://msdn.microsoft.com/en-us/library/system.invalidcastexception(v=vs.110).aspx \ No newline at end of file diff --git a/docs/guides/concepts/events.md b/docs/guides/concepts/events.md deleted file mode 100644 index 47db49aa8..000000000 --- a/docs/guides/concepts/events.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: Working with Events ---- - -Events in Discord.Net are consumed in a similar manner to the standard -convention, with the exception that every event must be of the type -`System.Threading.Tasks.Task` and instead of using `EventArgs`, the -event's parameters are passed directly into the handler. - -This allows for events to be handled in an async context directly -instead of relying on `async void`. - -### Usage - -To receive data from an event, hook into it using C#'s delegate -event pattern. - -You may either opt to hook an event to an anonymous function (lambda) -or a named function. - -### Safety - -All events are designed to be thread-safe; events are executed -synchronously off the gateway task in the same context as the gateway -task. - -As a side effect, this makes it possible to deadlock the gateway task -and kill a connection. As a general rule of thumb, any task that takes -longer than three seconds should **not** be awaited directly in the -context of an event, but should be wrapped in a `Task.Run` or -offloaded to another task. - -This also means that you should not await a task that requests data -from Discord's gateway in the same context of an event. Since the -gateway will wait on all invoked event handlers to finish before -processing any additional data from the gateway, this will create -a deadlock that will be impossible to recover from. - -Exceptions in commands will be swallowed by the gateway and logged out -through the client's log method. - -### Common Patterns - -As you may know, events in Discord.Net are only given a signature of -`Func`. There is no room for predefined argument names, -so you must either consult IntelliSense, or view the API documentation -directly. - -That being said, there are a variety of common patterns that allow you -to infer what the parameters in an event mean. - -#### Entity, Entity - -An event handler with a signature of `Func` -typically means that the first object will be a clone of the entity -_before_ a change was made, and the latter object will be an attached -model of the entity _after_ the change was made. - -This pattern is typically only found on `EntityUpdated` events. - -#### Cacheable - -An event handler with a signature of `Func` -means that the `before` state of the entity was not provided by the -API, so it can either be pulled from the client's cache or -downloaded from the API. - -See the documentation for [Cacheable] for more information on this -object. - -[Cacheable]: xref:Discord.Cacheable`2 - -### Samples - -[!code-csharp[Event Sample](samples/events.cs)] - -### Tips - -Many events relating to a Message entity (i.e. `MessageUpdated` and -`ReactionAdded`) rely on the client's message cache, which is -**not** enabled by default. Set the `MessageCacheSize` flag in -[DiscordSocketConfig] to enable it. - -[DiscordSocketConfig]: xref:Discord.WebSocket.DiscordSocketConfig \ No newline at end of file diff --git a/docs/guides/concepts/logging.md b/docs/guides/concepts/logging.md deleted file mode 100644 index 50d2e9546..000000000 --- a/docs/guides/concepts/logging.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: Logging ---- - -Discord.Net's clients provide a [Log] event that all messages will be -disbatched over. - -For more information about events in Discord.Net, see the [Events] -section. - -[Log]: xref:Discord.Rest.BaseDiscordClient#Discord_Rest_BaseDiscordClient_Log -[Events]: events.md - -### Usage - -To receive log events, simply hook the discord client's log method -to a `Task` with a single parameter of type [LogMessage]. - -It is recommended that you use an established function instead of a -lambda for handling logs, because most addons accept a reference -to a logging function to write their own messages. - -[LogMessage]: xref:Discord.LogMessage - -### Usage in Commands - -Discord.Net's [CommandService] also provides a log event, identical -in signature to other log events. - -Data logged through this event is typically coupled with a -[CommandException], where information about the command's context -and error can be found and handled. - -[CommandService]: xref:Discord.Commands.CommandService -[CommandException]: xref:Discord.Commands.CommandException - -#### Samples - -[!code-csharp[Logging Sample](samples/logging.cs)] - -#### Tips - -Due to the nature of Discord.Net's event system, all log event -handlers will be executed synchronously on the gateway thread. If your -log output will be dumped to a Web API (e.g. Sentry), you are advised -to wrap your output in a `Task.Run` so the gateway thread does not -become blocked while waiting for logging data to be written. \ No newline at end of file diff --git a/docs/guides/concepts/samples/connections.cs b/docs/guides/concepts/samples/connections.cs deleted file mode 100644 index f96251a39..000000000 --- a/docs/guides/concepts/samples/connections.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Discord; -using Discord.WebSocket; - -public class Program -{ - private DiscordSocketClient _client; - static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult(); - - public async Task MainAsync() - { - _client = new DiscordSocketClient(); - - await _client.LoginAsync(TokenType.Bot, "bot token"); - await _client.StartAsync(); - - Console.WriteLine("Press any key to exit..."); - Console.ReadKey(); - - await _client.StopAsync(); - // Wait a little for the client to finish disconnecting before allowing the program to return - await Task.Delay(500); - } -} \ No newline at end of file diff --git a/docs/guides/concepts/samples/entities.cs b/docs/guides/concepts/samples/entities.cs deleted file mode 100644 index 7655c44e9..000000000 --- a/docs/guides/concepts/samples/entities.cs +++ /dev/null @@ -1,13 +0,0 @@ -public string GetChannelTopic(ulong id) -{ - var channel = client.GetChannel(81384956881809408) as SocketTextChannel; - if (channel == null) return ""; - return channel.Topic; -} - -public string GuildOwner(SocketChannel channel) -{ - var guild = (channel as SocketGuildChannel)?.Guild; - if (guild == null) return ""; - return Context.Guild.Owner.Username; -} \ No newline at end of file diff --git a/docs/guides/concepts/samples/events.cs b/docs/guides/concepts/samples/events.cs deleted file mode 100644 index cf0492cb5..000000000 --- a/docs/guides/concepts/samples/events.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Discord; -using Discord.WebSocket; - -public class Program -{ - private DiscordSocketClient _client; - static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult(); - - public async Task MainAsync() - { - // When working with events that have Cacheable parameters, - // you must enable the message cache in your config settings if you plan to - // use the cached message entity. - var _config = new DiscordSocketConfig { MessageCacheSize = 100 }; - _client = new DiscordSocketClient(_config); - - await _client.LoginAsync(TokenType.Bot, "bot token"); - await _client.StartAsync(); - - _client.MessageUpdated += MessageUpdated; - _client.Ready += () => - { - Console.WriteLine("Bot is connected!"); - return Task.CompletedTask; - } - - await Task.Delay(-1); - } - - private async Task MessageUpdated(Cacheable before, SocketMessage after, ISocketMessageChannel channel) - { - // If the message was not in the cache, downloading it will result in getting a copy of `after`. - var message = await before.GetOrDownloadAsync(); - Console.WriteLine($"{message} -> {after}"); - } -} diff --git a/docs/guides/concepts/samples/logging.cs b/docs/guides/concepts/samples/logging.cs deleted file mode 100644 index a2ddf7b90..000000000 --- a/docs/guides/concepts/samples/logging.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Discord; -using Discord.WebSocket; - -public class Program -{ - private DiscordSocketClient _client; - static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult(); - - public async Task MainAsync() - { - _client = new DiscordSocketClient(new DiscordSocketConfig - { - LogLevel = LogSeverity.Info - }); - - _client.Log += Log; - - await _client.LoginAsync(TokenType.Bot, "bot token"); - await _client.StartAsync(); - - await Task.Delay(-1); - } - - private Task Log(LogMessage message) - { - Console.WriteLine(message.ToString()); - return Task.CompletedTask; - } -} \ No newline at end of file diff --git a/docs/guides/getting_started/images/install-rider-add.png b/docs/guides/getting_started/images/install-rider-add.png deleted file mode 100644 index 3f0dc729e..000000000 Binary files a/docs/guides/getting_started/images/install-rider-add.png and /dev/null differ diff --git a/docs/guides/getting_started/images/install-rider-nuget-manager.png b/docs/guides/getting_started/images/install-rider-nuget-manager.png deleted file mode 100644 index 884b32d6b..000000000 Binary files a/docs/guides/getting_started/images/install-rider-nuget-manager.png and /dev/null differ diff --git a/docs/guides/getting_started/images/install-rider-search.png b/docs/guides/getting_started/images/install-rider-search.png deleted file mode 100644 index 32f2f9722..000000000 Binary files a/docs/guides/getting_started/images/install-rider-search.png and /dev/null differ diff --git a/docs/guides/getting_started/images/install-vs-deps.png b/docs/guides/getting_started/images/install-vs-deps.png deleted file mode 100644 index ab10bd1bd..000000000 Binary files a/docs/guides/getting_started/images/install-vs-deps.png and /dev/null differ diff --git a/docs/guides/getting_started/images/install-vs-nuget.png b/docs/guides/getting_started/images/install-vs-nuget.png deleted file mode 100644 index 64da79a9f..000000000 Binary files a/docs/guides/getting_started/images/install-vs-nuget.png and /dev/null differ diff --git a/docs/guides/getting_started/images/intro-add-bot.png b/docs/guides/getting_started/images/intro-add-bot.png deleted file mode 100644 index e40997ed3..000000000 Binary files a/docs/guides/getting_started/images/intro-add-bot.png and /dev/null differ diff --git a/docs/guides/getting_started/images/intro-client-id.png b/docs/guides/getting_started/images/intro-client-id.png deleted file mode 100644 index e370aa2ec..000000000 Binary files a/docs/guides/getting_started/images/intro-client-id.png and /dev/null differ diff --git a/docs/guides/getting_started/images/intro-create-app.png b/docs/guides/getting_started/images/intro-create-app.png deleted file mode 100644 index 7aceb84b4..000000000 Binary files a/docs/guides/getting_started/images/intro-create-app.png and /dev/null differ diff --git a/docs/guides/getting_started/images/intro-create-bot.png b/docs/guides/getting_started/images/intro-create-bot.png deleted file mode 100644 index 0522358cf..000000000 Binary files a/docs/guides/getting_started/images/intro-create-bot.png and /dev/null differ diff --git a/docs/guides/getting_started/images/intro-token.png b/docs/guides/getting_started/images/intro-token.png deleted file mode 100644 index 8617cb76f..000000000 Binary files a/docs/guides/getting_started/images/intro-token.png and /dev/null differ diff --git a/docs/guides/getting_started/installing.md b/docs/guides/getting_started/installing.md deleted file mode 100644 index 5d4c85d81..000000000 --- a/docs/guides/getting_started/installing.md +++ /dev/null @@ -1,146 +0,0 @@ ---- -title: Installing Discord.Net ---- - -Discord.Net is distributed through the NuGet package manager, and it -is recommended to use NuGet to get started. - -Optionally, you may compile from source and install yourself. - -# Supported Platforms - -Currently, Discord.Net targets [.NET Standard] 1.3 and offers support -for .NET Standard 1.1. If your application will be targeting .NET -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 -required. When using .NET Framework, it is suggested to target -`.NET Framework 4.6.1` or higher. - -[.NET Standard]: https://docs.microsoft.com/en-us/dotnet/articles/standard/library -[.NET Core]: https://docs.microsoft.com/en-us/dotnet/articles/core/ -[additional steps]: #installing-on-net-standard-11 - -# Installing with NuGet - -Release builds of Discord.Net 1.0 will be published to the -[official NuGet feed]. - -Development builds of Discord.Net 1.0, as well as addons *(TODO)* are -published to our development [MyGet feed]. - -Direct feed link: `https://www.myget.org/F/discord-net/api/v3/index.json` - -Not sure how to add a direct feed? See how [with Visual Studio] or -[without Visual Studio]. - -[official NuGet feed]: https://nuget.org -[MyGet feed]: https://www.myget.org/feed/Packages/discord-net -[with Visual Studio]: https://docs.microsoft.com/en-us/nuget/tools/package-manager-ui#package-sources -[without Visual Studio]: #configuring-nuget-without-visual-studio - -## Using Visual Studio - -> [!TIP] ->Don't forget to change your package source if you're installing from -the developer feed. ->Also make sure to check "Enable Prereleases" if installing a dev -build! - -1. Create a solution for your bot. -2. In Solution Explorer, find the "Dependencies" element under your -bot's project. -3. Right click on "Dependencies", and select "Manage NuGet packages." -![Step 3](images/install-vs-deps.png) -4. In the "Browse" tab, search for `Discord.Net`. -5. Install the `Discord.Net` package. -![Step 5](images/install-vs-nuget.png) - -## Using JetBrains Rider - -> [!TIP] -Make sure to check the "Prerelease" box if installing a dev build! - -1. Create a new solution for your bot. -2. Open the NuGet window (Tools > NuGet > Manage NuGet packages for -Solution). -![Step 2](images/install-rider-nuget-manager.png) -3. In the "Packages" tab, search for `Discord.Net`. -![Step 3](images/install-rider-search.png) -4. Install by adding the package to your project. -![Step 4](images/install-rider-add.png) - -## Using Visual Studio Code - -> [!TIP] -Don't forget to add the package source to a [NuGet.Config file] if -you're installing from the developer feed. - -1. Create a new project for your bot. -2. Add `Discord.Net` to your .csproj. - -[!code-xml[Sample .csproj](samples/project.csproj)] - -[NuGet.Config file]: #configuring-nuget-without-visual-studio - -# Compiling from Source - -In order to compile Discord.Net, you require the following: - -### Using Visual Studio - -- [Visual Studio 2017](https://www.visualstudio.com/) -- [.NET Core SDK 1.0](https://www.microsoft.com/net/download/core#/sdk) - -The .NET Core and Docker (Preview) workload is required during Visual -Studio installation. - -### Using Command Line - -- [.NET Core SDK 1.0](https://www.microsoft.com/net/download/core#/sdk) - -# Additional Information - -## Installing on .NET Standard 1.1 - -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 -installed and configured. - -First, install the following packages through NuGet, or compile -yourself, if you prefer: - -- Discord.Net.Providers.WS4Net -- 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 -these custom providers over the default ones. - -To do this, set the `WebSocketProvider` and the optional -`UdpSocketProvider` properties on the [DiscordSocketConfig] that you -are passing into your client. - -[!code-csharp[NET Standard 1.1 Example](samples/netstd11.cs)] - -[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient -[DiscordSocketConfig]: xref:Discord.WebSocket.DiscordSocketConfig - -## Configuring NuGet without Visual Studio - -If you plan on deploying your bot or developing outside of Visual -Studio, you will need to create a local NuGet configuration file for -your project. - -To do this, create a file named `nuget.config` alongside the root of -your application, where the project solution is located. - -Paste the following snippets into this configuration file, adding any -additional feeds as necessary. - -[!code-xml[NuGet Configuration](samples/nuget.config)] diff --git a/docs/guides/getting_started/intro.md b/docs/guides/getting_started/intro.md deleted file mode 100644 index db086df21..000000000 --- a/docs/guides/getting_started/intro.md +++ /dev/null @@ -1,237 +0,0 @@ ---- -title: Getting Started ---- - -# 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. - -## Creating a Discord Bot - -Before you can begin writing your bot, it is necessary to create a bot -account on Discord. - -1. Visit the [Discord Applications Portal]. -2. Create a New Application. -3. Give the application a name (this will be the bot's initial -username). -4. Create the Application. - - ![Step 4](images/intro-create-app.png) - -5. In the application review page, click **Create a Bot User**. - - ![Step 5](images/intro-create-bot.png) - -6. Confirm the popup. -7. If this bot will be public, check "Public Bot." **Do not tick any -other options!** - -[Discord Applications Portal]: https://discordapp.com/developers/applications/me - -## Adding your bot to a server - -Bots **cannot** use invite links, they must be explicitly invited -through the OAuth2 flow. - -1. Open your bot's application on the [Discord Applications Portal]. -2. Retrieve the app's **Client ID**. - - ![Step 2](images/intro-client-id.png) - -3. Create an OAuth2 authorization URL -`https://discordapp.com/oauth2/authorize?client_id=&scope=bot` -4. Open the authorization URL in your browser. -5. Select a server. -6. Click on authorize. - - >[!NOTE] - Only servers where you have the `MANAGE_SERVER` permission will be - present in this list. - - ![Step 6](images/intro-add-bot.png) - - -## Connecting to Discord - -If you have not already created a project and installed Discord.Net, -do that now. (see the [Installing](installing.md) section) - -### Async - -Discord.Net uses .NET's [Task-based Asynchronous Pattern (TAP)] -extensively - nearly every operation is asynchronous. - -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 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)] - -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 -to Discord later on without needing to worry about setting up the -correct async implementation. - ->[!TIP] -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; -since our first non-async method is the program's `Main` method, this -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. - -[Task-based Asynchronous Pattern (TAP)]: https://docs.microsoft.com/en-us/dotnet/articles/csharp/async - -### Creating a logging method - -Before we create and configure a Discord client, we will add a method -to handle Discord.Net's log events. - -To allow agnostic support of as many log providers as possible, we -log information through a `Log` event with a proprietary `LogMessage` -parameter. See the [API Documentation] for this event. - -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 -the Console. - -[!code-csharp[Async Context](samples/intro/logging.cs)] - -[API Documentation]: xref:Discord.Rest.BaseDiscordClient#Discord_Rest_BaseDiscordClient_Log - -### 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](terminology.md) if you're 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 -users, the default will work fine. - -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. - -Next, you will need to "login to Discord" with the `LoginAsync` -method. - -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]). - -![Token](images/intro-token.png) - ->[!IMPORTANT] -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 -to store this token in an external file if you plan on distributing -the source code for your bot. - -We may now invoke the client's `StartAsync` method, which will -start connection/reconnection logic. It is important to note that -**this method returns as soon as connection logic has been started!** - -Any methods that rely on the client's state should go in an event -handler. - -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. - -The following lines can now be added: - -[!code-csharp[Create client](samples/intro/client.cs)] - -At this point, feel free to start your program and see your bot come -online in Discord. - ->[!TIP] -Encountering a `PlatformNotSupportedException` when starting your bot? -This means that you are targeting a platform where .NET's default -WebSocket client is not supported. Refer to the [installation guide] -for how to fix this. - -[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient -[installation guide]: installing.md#installing-on-net-standard-11 - -### Handling a 'ping' - ->[!WARNING] -Please note that this is *not* a proper way to create a command. -Use the `CommandService` provided by the library instead, as explained -in the [Command Guide] 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!". - -Since we want to listen for new messages, the event to hook into -is [MessageReceived]. - -In your program, add a method that matches the signature of the -`MessageReceived` event - it must be a method (`Func`) that returns -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 -it as `async`. - -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 -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 -parameter. - -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!". - -You should have now added the following lines: - -[!code-csharp[Message](samples/intro/message.cs)] - -Now 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 -commands, it is strongly recommended to use the command framework as -shown below. - -For your reference, you may view the [completed program]. - -[MessageReceived]: xref:Discord.WebSocket.DiscordSocketClient#Discord_WebSocket_DiscordSocketClient_MessageReceived -[SocketMessage]: xref:Discord.WebSocket.SocketMessage -[SocketMessageChannel]: xref:Discord.WebSocket.ISocketMessageChannel -[completed program]: samples/intro/complete.cs -[Command Guide]: ../commands/commands.md - -# Building a bot with commands - -This section will show you how to write a program that is ready for -[Commands](../commands/commands.md). Note that we will not be -explaining _how_ to write Commands or Services, it will only be -covering the general structure. - -For reference, view an [annotated example] of this structure. - -[annotated example]: samples/intro/structure.cs - -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). - -**todo:** diagram of bot structure \ No newline at end of file diff --git a/docs/guides/getting_started/samples/intro/async-context.cs b/docs/guides/getting_started/samples/intro/async-context.cs deleted file mode 100644 index c01ddec55..000000000 --- a/docs/guides/getting_started/samples/intro/async-context.cs +++ /dev/null @@ -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() - { - } - } -} \ No newline at end of file diff --git a/docs/guides/getting_started/samples/intro/client.cs b/docs/guides/getting_started/samples/intro/client.cs deleted file mode 100644 index a73082052..000000000 --- a/docs/guides/getting_started/samples/intro/client.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Program.cs -using Discord.WebSocket; -// ... -private DiscordSocketClient _client; -public async Task MainAsync() -{ - _client = new DiscordSocketClient(); - - _client.Log += Log; - - 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); -} diff --git a/docs/guides/getting_started/samples/intro/complete.cs b/docs/guides/getting_started/samples/intro/complete.cs deleted file mode 100644 index 23b59ce6f..000000000 --- a/docs/guides/getting_started/samples/intro/complete.cs +++ /dev/null @@ -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; - } - } -} diff --git a/docs/guides/getting_started/samples/intro/logging.cs b/docs/guides/getting_started/samples/intro/logging.cs deleted file mode 100644 index 4fb85a063..000000000 --- a/docs/guides/getting_started/samples/intro/logging.cs +++ /dev/null @@ -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; - } - } -} \ No newline at end of file diff --git a/docs/guides/getting_started/samples/intro/message.cs b/docs/guides/getting_started/samples/intro/message.cs deleted file mode 100644 index d6fd90778..000000000 --- a/docs/guides/getting_started/samples/intro/message.cs +++ /dev/null @@ -1,14 +0,0 @@ -public async Task MainAsync() -{ - // client.Log ... - _client.MessageReceived += MessageReceived; - // ... -} - -private async Task MessageReceived(SocketMessage message) -{ - if (message.Content == "!ping") - { - await message.Channel.SendMessageAsync("Pong!"); - } -} diff --git a/docs/guides/getting_started/samples/intro/structure.cs b/docs/guides/getting_started/samples/intro/structure.cs deleted file mode 100644 index a9a018c3a..000000000 --- a/docs/guides/getting_started/samples/intro/structure.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Discord; -using Discord.Commands; -using Discord.WebSocket; - -class Program -{ - // Program entry point - static void Main(string[] args) - { - // Call the Program constructor, followed by the - // MainAsync method and wait until it finishes (which should be never). - new Program().MainAsync().GetAwaiter().GetResult(); - } - - private readonly DiscordSocketClient _client; - - // Keep the CommandService and DI container around for use with commands. - // These two types require you install the Discord.Net.Commands package. - private readonly CommandService _commands; - private readonly IServiceProvider _services; - - private Program() - { - _client = new DiscordSocketClient(new DiscordSocketConfig - { - // How much logging do you want to see? - LogLevel = LogSeverity.Info, - - // If you or another service needs to do anything with messages - // (eg. checking Reactions, checking the content of edited/deleted messages), - // you must set the MessageCacheSize. You may adjust the number as needed. - //MessageCacheSize = 50, - - // If your platform doesn't have native websockets, - // add Discord.Net.Providers.WS4Net from NuGet, - // add the `using` at the top, and uncomment this line: - //WebSocketProvider = WS4NetProvider.Instance - }); - - _commands = new CommandService(new CommandServiceConfig - { - // Again, log level: - LogLevel = LogSeverity.Info, - - // There's a few more properties you can set, - // for example, case-insensitive commands. - CaseSensitiveCommands = false, - }); - - // Subscribe the logging handler to both the client and the CommandService. - _client.Log += Log; - _commands.Log += Log; - - // Setup your DI container. - _services = ConfigureServices(), - - } - - // If any services require the client, or the CommandService, or something else you keep on hand, - // pass them as parameters into this method as needed. - // If this method is getting pretty long, you can seperate it out into another file using partials. - private static IServiceProvider ConfigureServices() - { - var map = new ServiceCollection() - // Repeat this for all the service classes - // and other dependencies that your commands might need. - .AddSingleton(new SomeServiceClass()); - - // When all your required services are in the collection, build the container. - // Tip: There's an overload taking in a 'validateScopes' bool to make sure - // you haven't made any mistakes in your dependency graph. - return map.BuildServiceProvider(); - } - - // Example of a logging handler. This can be re-used by addons - // that ask for a Func. - private static Task Log(LogMessage message) - { - switch (message.Severity) - { - case LogSeverity.Critical: - case LogSeverity.Error: - Console.ForegroundColor = ConsoleColor.Red; - break; - case LogSeverity.Warning: - Console.ForegroundColor = ConsoleColor.Yellow; - break; - case LogSeverity.Info: - Console.ForegroundColor = ConsoleColor.White; - break; - case LogSeverity.Verbose: - case LogSeverity.Debug: - Console.ForegroundColor = ConsoleColor.DarkGray; - break; - } - Console.WriteLine($"{DateTime.Now,-19} [{message.Severity,8}] {message.Source}: {message.Message} {message.Exception}"); - Console.ResetColor(); - - // If you get an error saying 'CompletedTask' doesn't exist, - // your project is targeting .NET 4.5.2 or lower. You'll need - // to adjust your project's target framework to 4.6 or higher - // (instructions for this are easily Googled). - // If you *need* to run on .NET 4.5 for compat/other reasons, - // the alternative is to 'return Task.Delay(0);' instead. - return Task.CompletedTask; - } - - private async Task MainAsync() - { - // Centralize the logic for commands into a separate method. - await InitCommands(); - - // Login and connect. - await _client.LoginAsync(TokenType.Bot, /* */); - await _client.StartAsync(); - - // Wait infinitely so your bot actually stays connected. - await Task.Delay(Timeout.Infinite); - } - - private async Task InitCommands() - { - // Either search the program and add all Module classes that can be found. - // Module classes MUST be marked 'public' or they will be ignored. - // You also need to pass your 'IServiceProvider' instance now, - // so make sure that's done before you get here. - await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services); - // Or add Modules manually if you prefer to be a little more explicit: - await _commands.AddModuleAsync(_services); - // Note that the first one is 'Modules' (plural) and the second is 'Module' (singular). - - // Subscribe a handler to see if a message invokes a command. - _client.MessageReceived += HandleCommandAsync; - } - - private async Task HandleCommandAsync(SocketMessage arg) - { - // Bail out if it's a System Message. - var msg = arg as SocketUserMessage; - if (msg == null) return; - - // We don't want the bot to respond to itself or other bots. - if (msg.Author.Id == _client.CurrentUser.Id || msg.Author.IsBot) return; - - // Create a number to track where the prefix ends and the command begins - int pos = 0; - // Replace the '!' with whatever character - // you want to prefix your commands with. - // Uncomment the second half if you also want - // commands to be invoked by mentioning the bot instead. - if (msg.HasCharPrefix('!', ref pos) /* || msg.HasMentionPrefix(_client.CurrentUser, ref pos) */) - { - // Create a Command Context. - var context = new SocketCommandContext(_client, msg); - - // Execute the command. (result does not indicate a return value, - // rather an object stating if the command executed successfully). - var result = await _commands.ExecuteAsync(context, pos); - - // Uncomment the following lines if you want the bot - // to send a message if it failed. - // This does not catch errors from commands with 'RunMode.Async', - // subscribe a handler for '_commands.CommandExecuted' to see those. - //if (!result.IsSuccess && result.Error != CommandError.UnknownCommand) - // await msg.Channel.SendMessageAsync(result.ErrorReason); - } - } -} diff --git a/docs/guides/getting_started/samples/netstd11.cs b/docs/guides/getting_started/samples/netstd11.cs deleted file mode 100644 index a8573696a..000000000 --- a/docs/guides/getting_started/samples/netstd11.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Discord.Providers.WS4Net; -using Discord.Providers.UDPClient; -using Discord.WebSocket; -// ... -var client = new DiscordSocketClient(new DiscordSocketConfig -{ - WebSocketProvider = WS4NetProvider.Instance, - UdpSocketProvider = UDPClientProvider.Instance, -}); \ No newline at end of file diff --git a/docs/guides/getting_started/samples/nuget.config b/docs/guides/getting_started/samples/nuget.config deleted file mode 100644 index bf706a08b..000000000 --- a/docs/guides/getting_started/samples/nuget.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/docs/guides/getting_started/samples/project.csproj b/docs/guides/getting_started/samples/project.csproj deleted file mode 100644 index feb0b0c40..000000000 --- a/docs/guides/getting_started/samples/project.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - Exe - netcoreapp1.1 - true - - - - - - - diff --git a/docs/guides/getting_started/terminology.md b/docs/guides/getting_started/terminology.md deleted file mode 100644 index 74f7a6259..000000000 --- a/docs/guides/getting_started/terminology.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -uid: Terminology -title: Terminology ---- - -# Terminology - -## Preface - -Most terms for objects remain the same between 0.9 and 1.0. The major -difference is that the ``Server`` is now called ``Guild`` to stay in -line with Discord internally. - -## Implementation Specific Entities - -Discord.Net 1.0 is split into a core library and three different -implementations - `Discord.Net.Core`, `Discord.Net.Rest`, -`Discord.Net.Rpc`, and `Discord.Net.WebSockets`. - -As a bot developer, you will only need to use `Discord.Net.WebSockets`, -but you should be aware of the differences between them. - -`Discord.Net.Core` provides a set of interfaces that models Discord's -API. These interfaces are consistent throughout all implementations of -Discord.Net, and if you are writing an implementation-agnostic library -or addon, you can rely on the core interfaces to ensure that your -addon will run on all platforms. - -`Discord.Net.Rest` provides a set of concrete classes to be used -**strictly** with the REST portion of Discord's API. Entities in this -implementation are prefixed with `Rest` (e.g. `RestChannel`). - -`Discord.Net.Rpc` provides a set of concrete classes that are used -with Discord's RPC API. Entities in this implementation are prefixed -with `Rpc` (e.g. `RpcChannel`). - -`Discord.Net.WebSocket` provides a set of concrete classes that are -used primarily with Discord's WebSocket API or entities that are kept -in cache. When developing bots, you will be using this implementation. -All entities are prefixed with `Socket` (e.g. `SocketChannel`). \ No newline at end of file diff --git a/docs/guides/migrating/migrating.md b/docs/guides/migrating/migrating.md deleted file mode 100644 index bc628a5f8..000000000 --- a/docs/guides/migrating/migrating.md +++ /dev/null @@ -1,61 +0,0 @@ -# Migrating from 0.9 - -**1.0.0 is the biggest breaking change the library has gone through, due to massive -changes in the design of the library.** - ->A medium to advanced understanding is recommended when working with this library. - -It is recommended to familiarize yourself with the entities in 1.0 before continuing. -Feel free to look through the library's source directly, look through IntelliSense, or -look through our hosted [API Documentation](xref:Discord). - -## Entities - -Most API models function _similarly_ to 0.9, however their names have been changed. -You should also keep in mind that we now separate different types of Channels and Users. - -Before proceeding, please read over @Terminology to understand the naming behind some objects. - -Below is a table that compares most common 0.9 entities to their 1.0 counterparts. - ->This should be used mostly for migration purposes. Please take some time to consider whether ->or not you are using the right "tool for the job" when working with 1.0 - -| 0.9 | 1.0 | Notice | -| --- | --- | ------ | -| Server | @Discord.WebSocket.SocketGuild | -| Channel | @Discord.WebSocket.SocketGuildChannel | Applies only to channels that are members of a Guild | -| Channel.IsPrivate | @Discord.WebSocket.SocketDMChannel -| ChannelType.Text | @Discord.WebSocket.SocketTextChannel | This applies only to Text Channels in Guilds -| ChannelType.Voice | @Discord.WebSocket.SocketVoiceChannel | This applies only to Voice Channels in Guilds -| User | @Discord.WebSocket.SocketGuildUser | This applies only to users belonging to a Guild* -| Profile | @Discord.WebSocket.SocketGuildUser -| Message | @Discord.WebSocket.SocketUserMessage - -\* To retrieve an @Discord.WebSocket.SocketGuildUser, you must retrieve the user from an @Discord.WebSocket.SocketGuild. - -## Event Registration - -Prior to 1.0, events were registered using the standard c# `Handler(EventArgs)` pattern. In 1.0, -events are delegates, but are still registered the same. - -For example, let's look at [DiscordSocketClient.MessageReceived](xref:Discord.WebSocket.DiscordSocketClient#Discord_WebSocket_DiscordSocketClient_MessageReceived) - -To hook an event into MessageReceived, we now use the following code: -[!code-csharp[Event Registration](samples/event.cs)] - -> **All Event Handlers in 1.0 MUST return Task!** - -If your event handler is marked as `async`, it will automatically return `Task`. However, -if you do not need to execute asynchronus code, do _not_ mark your handler as `async`, and instead, -stick a `return Task.CompletedTask` at the bottom. - -[!code-csharp[Sync Event Registration](samples/sync_event.cs)] - -**Event handlers no longer require a sender.** The only arguments your event handler needs to accept -are the parameters used by the event. It is recommended to look at the event in IntelliSense or on the -API docs before implementing it. - -## Async - -Nearly everything in 1.0 is an async Task. You should always await any tasks you invoke. diff --git a/docs/guides/migrating/samples/event.cs b/docs/guides/migrating/samples/event.cs deleted file mode 100644 index 8719942f2..000000000 --- a/docs/guides/migrating/samples/event.cs +++ /dev/null @@ -1,4 +0,0 @@ -_client.MessageReceived += async (msg) => -{ - await msg.Channel.SendMessageAsync(msg.Content); -} \ No newline at end of file diff --git a/docs/guides/migrating/samples/sync_event.cs b/docs/guides/migrating/samples/sync_event.cs deleted file mode 100644 index f4a55cdd3..000000000 --- a/docs/guides/migrating/samples/sync_event.cs +++ /dev/null @@ -1,5 +0,0 @@ -_client.Log += (msg) => -{ - Console.WriteLine(msg.ToString()); - return Task.CompletedTask; -} \ No newline at end of file diff --git a/docs/guides/toc.yml b/docs/guides/toc.yml deleted file mode 100644 index 2e3a61e19..000000000 --- a/docs/guides/toc.yml +++ /dev/null @@ -1,27 +0,0 @@ -- name: Getting Started - items: - - name: Installation - href: getting_started/installing.md - - name: Your First Bot - href: getting_started/intro.md - - name: Terminology - href: getting_started/terminology.md -- name: Basic Concepts - items: - - name: Logging Data - href: concepts/logging.md - - name: Working with Events - href: concepts/events.md - - name: Managing Connections - href: concepts/connections.md - - name: Entities - href: concepts/entities.md -- name: The Command Service - items: - - name: Command Guide - href: commands/commands.md -- name: Voice - items: - - name: Voice Guide - href: voice/sending-voice.md -- name: Migrating from 0.9 \ No newline at end of file diff --git a/docs/guides/voice/samples/audio_create_ffmpeg.cs b/docs/guides/voice/samples/audio_create_ffmpeg.cs deleted file mode 100644 index dda560efe..000000000 --- a/docs/guides/voice/samples/audio_create_ffmpeg.cs +++ /dev/null @@ -1,10 +0,0 @@ -private Process CreateStream(string path) -{ - return Process.Start(new ProcessStartInfo - { - FileName = "ffmpeg", - Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1", - UseShellExecute = false, - RedirectStandardOutput = true, - }); -} diff --git a/docs/guides/voice/samples/audio_ffmpeg.cs b/docs/guides/voice/samples/audio_ffmpeg.cs deleted file mode 100644 index d36fbbc20..000000000 --- a/docs/guides/voice/samples/audio_ffmpeg.cs +++ /dev/null @@ -1,11 +0,0 @@ -private async Task SendAsync(IAudioClient client, string path) -{ - // Create FFmpeg using the previous example - using (var ffmpeg = CreateStream(path)) - using (var output = ffmpeg.StandardOutput.BaseStream) - using (var discord = client.CreatePCMStream(AudioApplication.Mixed)) - { - try { await output.CopyToAsync(discord); } - finally { await discord.FlushAsync(); } - } -} diff --git a/docs/guides/voice/samples/joining_audio.cs b/docs/guides/voice/samples/joining_audio.cs deleted file mode 100644 index 4cec67540..000000000 --- a/docs/guides/voice/samples/joining_audio.cs +++ /dev/null @@ -1,10 +0,0 @@ -[Command("join")] -public async Task JoinChannel(IVoiceChannel channel = null) -{ - // Get the audio channel - channel = channel ?? (msg.Author as IGuildUser)?.VoiceChannel; - if (channel == null) { await msg.Channel.SendMessageAsync("User must be in a voice channel, or a voice channel must be passed as an argument."); return; } - - // For the next step with transmitting audio, you would want to pass this Audio Client in to a service. - var audioClient = await channel.ConnectAsync(); -} diff --git a/docs/guides/voice/sending-voice.md b/docs/guides/voice/sending-voice.md deleted file mode 100644 index 024a98b95..000000000 --- a/docs/guides/voice/sending-voice.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: Sending Voice ---- - -**Information on this page is subject to change!** - ->[!WARNING] ->This article is out of date, and has not been rewritten yet. -Information is not guaranteed to be accurate. - -## Installing - -Audio requires two native libraries, `libsodium` and `opus`. -Both of these libraries must be placed in the runtime directory of your -bot. (When developing on .NET Framework, this would be `bin/debug`, -when developing on .NET Core, this is where you execute `dotnet run` -from; typically the same directory as your csproj). - -For Windows Users, precompiled binaries are available for your -convienence [here](https://discord.foxbot.me/binaries/). - -For Linux Users, you will need to compile [Sodium] and [Opus] from -source, or install them from your package manager. - -[Sodium]: https://download.libsodium.org/libsodium/releases/ -[Opus]: http://downloads.xiph.org/releases/opus/ - -## Joining a Channel - -Joining a channel is the first step to sending audio, and will return -an [IAudioClient] to send data with. - -To join a channel, simply await [ConnectAsync] on any instance of an -@Discord.IAudioChannel. - -[!code-csharp[Joining a Channel](samples/joining_audio.cs)] - -The client will sustain a connection to this channel until it is -kicked, disconnected from Discord, or told to disconnect. - -It should be noted that voice connections are created on a per-guild -basis; only one audio connection may be open by the bot in a single -guild. To switch channels within a guild, invoke [ConnectAsync] on -another voice channel in the guild. - -[IAudioClient]: xref:Discord.Audio.IAudioClient -[ConnectAsync]: xref:Discord.IAudioChannel#Discord_IAudioChannel_ConnectAsync_Action_IAudioClient__ - -## Transmitting Audio - -### With FFmpeg - -[FFmpeg] is an open source, highly versatile AV-muxing tool. This is -the recommended method of transmitting audio. - -Before you begin, you will need to have a version of FFmpeg downloaded -and placed somewhere in your PATH (or alongside the bot, in the same -location as libsodium and opus). Windows binaries are available on -[FFmpeg's download page]. - -[FFmpeg]: https://ffmpeg.org/ -[FFmpeg's download page]: https://ffmpeg.org/download.html - -First, you will need to create a Process that starts FFmpeg. An -example of how to do this is included below, though it is important -that you return PCM at 48000hz. - ->[!NOTE] ->As of the time of this writing, Discord.Audio struggles significantly ->with processing audio that is already opus-encoded; you will need to ->use the PCM write streams. - -[!code-csharp[Creating FFmpeg](samples/audio_create_ffmpeg.cs)] - -Next, to transmit audio from FFmpeg to Discord, you will need to -pull an [AudioOutStream] from your [IAudioClient]. Since we're using -PCM audio, use [IAudioClient.CreatePCMStream]. - -The sample rate argument doesn't particularly matter, so long as it is -a valid rate (120, 240, 480, 960, 1920, or 2880). For the sake of -simplicity, I recommend using 1920. - -Channels should be left at `2`, unless you specified a different value -for `-ac 2` when creating FFmpeg. - -[AudioOutStream]: xref:Discord.Audio.AudioOutStream -[IAudioClient.CreatePCMStream]: xref:Discord.Audio.IAudioClient#Discord_Audio_IAudioClient_CreateDirectPCMStream_Discord_Audio_AudioApplication_System_Nullable_System_Int32__System_Int32_ - -Finally, audio will need to be piped from FFmpeg's stdout into your -AudioOutStream. This step can be as complex as you'd like it to be, but -for the majority of cases, you can just use [Stream.CopyToAsync], as -shown below. - -[Stream.CopyToAsync]: https://msdn.microsoft.com/en-us/library/hh159084(v=vs.110).aspx - -If you are implementing a queue for sending songs, it's likely that -you will want to wait for audio to stop playing before continuing on -to the next song. You can await `AudioOutStream.FlushAsync` to wait for -the audio client's internal buffer to clear out. - -[!code-csharp[Sending Audio](samples/audio_ffmpeg.cs)] \ No newline at end of file diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index ef9ecdfdd..000000000 --- a/docs/index.md +++ /dev/null @@ -1,13 +0,0 @@ - -# Discord.Net Documentation - -Discord.Net is an asynchronous, multiplatform .NET Library used to interface with the [Discord API](https://discordapp.com/). - -If this is your first time using Discord.Net, you should refer to the [Intro](guides/getting_started/intro.md) for tutorials. -More experienced users might refer to the [API Documentation](api/index.md) for a breakdown of the individuals objects in the library. - -For additional resources: - - [Discord API Guild](https://discord.gg/discord-api) - Look for `#dotnet_discord-net` - - [GitHub](https://github.com/RogueException/Discord.Net/tree/dev) - - [NuGet](https://www.nuget.org/packages/Discord.Net/) - - [MyGet Feed](https://www.myget.org/feed/Packages/discord-net) - Addons and nightly builds \ No newline at end of file diff --git a/docs/toc.yml b/docs/toc.yml deleted file mode 100644 index c08e708bf..000000000 --- a/docs/toc.yml +++ /dev/null @@ -1,6 +0,0 @@ - -- name: Guides - href: guides/ -- name: API Documentation - href: api/ - homepage: api/index.md