Browse Source

I dont need nu docs

pull/1170/head
Adomix 7 years ago
parent
commit
1c52d79654
56 changed files with 0 additions and 2089 deletions
  1. +0
    -10
      docs/.gitignore
  2. +0
    -46
      docs/CONTRIBUTING.md
  3. +0
    -16
      docs/README.md
  4. +0
    -6
      docs/api/.gitignore
  5. +0
    -13
      docs/api/index.md
  6. +0
    -74
      docs/docfx.json
  7. +0
    -11
      docs/filterConfig.yml
  8. +0
    -343
      docs/guides/commands/commands.md
  9. +0
    -63
      docs/guides/commands/samples/command_handler.cs
  10. +0
    -18
      docs/guides/commands/samples/dependency_map_setup.cs
  11. +0
    -40
      docs/guides/commands/samples/dependency_module.cs
  12. +0
    -6
      docs/guides/commands/samples/empty-module.cs
  13. +0
    -18
      docs/guides/commands/samples/groups.cs
  14. +0
    -41
      docs/guides/commands/samples/module.cs
  15. +0
    -24
      docs/guides/commands/samples/require_owner.cs
  16. +0
    -15
      docs/guides/commands/samples/typereader.cs
  17. +0
    -58
      docs/guides/concepts/connections.md
  18. +0
    -71
      docs/guides/concepts/entities.md
  19. +0
    -84
      docs/guides/concepts/events.md
  20. +0
    -47
      docs/guides/concepts/logging.md
  21. +0
    -23
      docs/guides/concepts/samples/connections.cs
  22. +0
    -13
      docs/guides/concepts/samples/entities.cs
  23. +0
    -36
      docs/guides/concepts/samples/events.cs
  24. +0
    -29
      docs/guides/concepts/samples/logging.cs
  25. BIN
      docs/guides/getting_started/images/install-rider-add.png
  26. BIN
      docs/guides/getting_started/images/install-rider-nuget-manager.png
  27. BIN
      docs/guides/getting_started/images/install-rider-search.png
  28. BIN
      docs/guides/getting_started/images/install-vs-deps.png
  29. BIN
      docs/guides/getting_started/images/install-vs-nuget.png
  30. BIN
      docs/guides/getting_started/images/intro-add-bot.png
  31. BIN
      docs/guides/getting_started/images/intro-client-id.png
  32. BIN
      docs/guides/getting_started/images/intro-create-app.png
  33. BIN
      docs/guides/getting_started/images/intro-create-bot.png
  34. BIN
      docs/guides/getting_started/images/intro-token.png
  35. +0
    -146
      docs/guides/getting_started/installing.md
  36. +0
    -237
      docs/guides/getting_started/intro.md
  37. +0
    -15
      docs/guides/getting_started/samples/intro/async-context.cs
  38. +0
    -17
      docs/guides/getting_started/samples/intro/client.cs
  39. +0
    -44
      docs/guides/getting_started/samples/intro/complete.cs
  40. +0
    -22
      docs/guides/getting_started/samples/intro/logging.cs
  41. +0
    -14
      docs/guides/getting_started/samples/intro/message.cs
  42. +0
    -173
      docs/guides/getting_started/samples/intro/structure.cs
  43. +0
    -9
      docs/guides/getting_started/samples/netstd11.cs
  44. +0
    -6
      docs/guides/getting_started/samples/nuget.config
  45. +0
    -13
      docs/guides/getting_started/samples/project.csproj
  46. +0
    -40
      docs/guides/getting_started/terminology.md
  47. +0
    -61
      docs/guides/migrating/migrating.md
  48. +0
    -4
      docs/guides/migrating/samples/event.cs
  49. +0
    -5
      docs/guides/migrating/samples/sync_event.cs
  50. +0
    -27
      docs/guides/toc.yml
  51. +0
    -10
      docs/guides/voice/samples/audio_create_ffmpeg.cs
  52. +0
    -11
      docs/guides/voice/samples/audio_ffmpeg.cs
  53. +0
    -10
      docs/guides/voice/samples/joining_audio.cs
  54. +0
    -101
      docs/guides/voice/sending-voice.md
  55. +0
    -13
      docs/index.md
  56. +0
    -6
      docs/toc.yml

+ 0
- 10
docs/.gitignore View File

@@ -1,10 +0,0 @@

###############
# folder #
###############
/**/DROP/
/**/TEMP/
/**/packages/
/**/bin/
/**/obj/
_site

+ 0
- 46
docs/CONTRIBUTING.md View File

@@ -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/

+ 0
- 16
docs/README.md View File

@@ -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

+ 0
- 6
docs/api/.gitignore View File

@@ -1,6 +0,0 @@

###############
# temp file #
###############
*.yml
.manifest

+ 0
- 13
docs/api/index.md View File

@@ -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

+ 0
- 74
docs/docfx.json View File

@@ -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
}
}

+ 0
- 11
docs/filterConfig.yml View File

@@ -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$

+ 0
- 343
docs/guides/commands/commands.md View File

@@ -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_

+ 0
- 63
docs/guides/commands/samples/command_handler.cs View File

@@ -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);
}
}

+ 0
- 18
docs/guides/commands/samples/dependency_map_setup.cs View File

@@ -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<DatabaseService>()
.BuildServiceProvider();
// ...
await _commands.AddModulesAsync(Assembly.GetEntryAssembly());
}

+ 0
- 40
docs/guides/commands/samples/dependency_module.cs View File

@@ -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;
}

}

+ 0
- 6
docs/guides/commands/samples/empty-module.cs View File

@@ -1,6 +0,0 @@
using Discord.Commands;

public class InfoModule : ModuleBase<SocketCommandContext>
{
}

+ 0
- 18
docs/guides/commands/samples/groups.cs View File

@@ -1,18 +0,0 @@
[Group("admin")]
public class AdminModule : ModuleBase<SocketCommandContext>
{
[Group("clean")]
public class CleanModule : ModuleBase<SocketCommandContext>
{
// ~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) { }
}

+ 0
- 41
docs/guides/commands/samples/module.cs View File

@@ -1,41 +0,0 @@
// Create a module with no prefix
public class Info : ModuleBase<SocketCommandContext>
{
// ~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<SocketCommandContext>
{
// ~sample square 20 -> 400
[Command("square")]
[Summary("Squares a number.")]
public async Task SquareAsync([Summary("The number to square.")] int num)
{
// We can also access the channel from the Command Context.
await Context.Channel.SendMessageAsync($"{num}^2 = {Math.Pow(num, 2)}");
}

// ~sample userinfo --> foxbot#0282
// ~sample userinfo @Khionu --> Khionu#8708
// ~sample userinfo Khionu#8708 --> Khionu#8708
// ~sample userinfo Khionu --> Khionu#8708
// ~sample userinfo 96642168176807936 --> Khionu#8708
// ~sample whois 96642168176807936 --> Khionu#8708
[Command("userinfo")]
[Summary("Returns info about the current user, or the user parameter, if one passed.")]
[Alias("user", "whois")]
public async Task UserInfoAsync([Summary("The (optional) user to get info for")] SocketUser user = null)
{
var userInfo = user ?? Context.Client.CurrentUser;
await ReplyAsync($"{userInfo.Username}#{userInfo.Discriminator}");
}
}

+ 0
- 24
docs/guides/commands/samples/require_owner.cs View File

@@ -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<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services)
{
// Get the ID of the bot's owner
var ownerId = (await services.GetService<DiscordSocketClient>().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.");
}
}

+ 0
- 15
docs/guides/commands/samples/typereader.cs View File

@@ -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<TypeReaderResult> 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."));
}
}

+ 0
- 58
docs/guides/concepts/connections.md View File

@@ -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

+ 0
- 71
docs/guides/concepts/entities.md View File

@@ -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

+ 0
- 84
docs/guides/concepts/events.md View File

@@ -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<T1, ..., Task>`. 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<Entity, Entity, Task>`
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<Cacheable, Entity, Task>`
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

+ 0
- 47
docs/guides/concepts/logging.md View File

@@ -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.

+ 0
- 23
docs/guides/concepts/samples/connections.cs View File

@@ -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);
}
}

+ 0
- 13
docs/guides/concepts/samples/entities.cs View File

@@ -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;
}

+ 0
- 36
docs/guides/concepts/samples/events.cs View File

@@ -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<IMessage, ulong> 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<IMessage, ulong> 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}");
}
}

+ 0
- 29
docs/guides/concepts/samples/logging.cs View File

@@ -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;
}
}

BIN
docs/guides/getting_started/images/install-rider-add.png View File

Before After
Width: 910  |  Height: 225  |  Size: 24 kB

BIN
docs/guides/getting_started/images/install-rider-nuget-manager.png View File

Before After
Width: 522  |  Height: 326  |  Size: 18 kB

BIN
docs/guides/getting_started/images/install-rider-search.png View File

Before After
Width: 462  |  Height: 222  |  Size: 12 kB

BIN
docs/guides/getting_started/images/install-vs-deps.png View File

Before After
Width: 495  |  Height: 272  |  Size: 13 kB

BIN
docs/guides/getting_started/images/install-vs-nuget.png View File

Before After
Width: 1563  |  Height: 936  |  Size: 120 kB

BIN
docs/guides/getting_started/images/intro-add-bot.png View File

Before After
Width: 500  |  Height: 512  |  Size: 26 kB

BIN
docs/guides/getting_started/images/intro-client-id.png View File

Before After
Width: 340  |  Height: 130  |  Size: 5.1 kB

BIN
docs/guides/getting_started/images/intro-create-app.png View File

Before After
Width: 962  |  Height: 716  |  Size: 52 kB

BIN
docs/guides/getting_started/images/intro-create-bot.png View File

Before After
Width: 763  |  Height: 769  |  Size: 46 kB

BIN
docs/guides/getting_started/images/intro-token.png View File

Before After
Width: 700  |  Height: 339  |  Size: 27 kB

+ 0
- 146
docs/guides/getting_started/installing.md View File

@@ -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)]

+ 0
- 237
docs/guides/getting_started/intro.md View File

@@ -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=<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

+ 0
- 15
docs/guides/getting_started/samples/intro/async-context.cs View File

@@ -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()
{
}
}
}

+ 0
- 17
docs/guides/getting_started/samples/intro/client.cs View File

@@ -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);
}

+ 0
- 44
docs/guides/getting_started/samples/intro/complete.cs View File

@@ -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;
}
}
}

+ 0
- 22
docs/guides/getting_started/samples/intro/logging.cs View File

@@ -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;
}
}
}

+ 0
- 14
docs/guides/getting_started/samples/intro/message.cs View File

@@ -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!");
}
}

+ 0
- 173
docs/guides/getting_started/samples/intro/structure.cs View File

@@ -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<LogMessage, Task>.
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, /* <DON'T HARDCODE YOUR TOKEN> */);
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<SomeModule>(_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);
}
}
}

+ 0
- 9
docs/guides/getting_started/samples/netstd11.cs View File

@@ -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,
});

+ 0
- 6
docs/guides/getting_started/samples/nuget.config View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="discord.net ci feed" value="https://www.myget.org/F/discord-net/api/v3/index.json" />
</packageSources>
</configuration>

+ 0
- 13
docs/guides/getting_started/samples/project.csproj View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Discord.Net" Version="1.*" />
</ItemGroup>

</Project>

+ 0
- 40
docs/guides/getting_started/terminology.md View File

@@ -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`).

+ 0
- 61
docs/guides/migrating/migrating.md View File

@@ -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.

+ 0
- 4
docs/guides/migrating/samples/event.cs View File

@@ -1,4 +0,0 @@
_client.MessageReceived += async (msg) =>
{
await msg.Channel.SendMessageAsync(msg.Content);
}

+ 0
- 5
docs/guides/migrating/samples/sync_event.cs View File

@@ -1,5 +0,0 @@
_client.Log += (msg) =>
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}

+ 0
- 27
docs/guides/toc.yml View File

@@ -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

+ 0
- 10
docs/guides/voice/samples/audio_create_ffmpeg.cs View File

@@ -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,
});
}

+ 0
- 11
docs/guides/voice/samples/audio_ffmpeg.cs View File

@@ -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(); }
}
}

+ 0
- 10
docs/guides/voice/samples/joining_audio.cs View File

@@ -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();
}

+ 0
- 101
docs/guides/voice/sending-voice.md View File

@@ -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)]

+ 0
- 13
docs/index.md View File

@@ -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

+ 0
- 6
docs/toc.yml View File

@@ -1,6 +0,0 @@

- name: Guides
href: guides/
- name: API Documentation
href: api/
homepage: api/index.md

Loading…
Cancel
Save