Restructure documentation layout

This commit is contained in:
Christopher F
2017-04-03 16:36:26 -04:00
parent b4c3427ed1
commit 5ade1e387b
41 changed files with 22 additions and 33 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,130 @@
---
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](#installing-on-net-standard-11).
Since Discord.Net is built on the .NET Standard, it is also recommended to
create applications using [.NET Core], though you are not required to. When
using .NET Framework, it is suggested to target `.NET 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/
# 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](#configuring-nuget-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
## Using Visual Studio
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'
> [!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!
5. Install the 'Discord.Net' package
![Step 5](images/install-vs-nuget.png)
## Using JetBrains Rider
**todo**
## Using Visual Studio Code
1. Create a new project for your bot
2. Add Discord.Net to your .csproj
[!code-xml[Sample .csproj](samples/project.csproj)]
> [!TIP]
Don't forget to add the package source to a [NuGet.Config file](#configuring-nuget-without-visual-studio) if you're installing from the
developer feed.
# 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 optionally `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)]

View File

@@ -0,0 +1,227 @@
---
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 **can not** 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
>[!NOTE]
Only servers where you have the `MANAGE_SERVER` permission will be
present in this list.
6. Click authorize
![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 be 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 immidiately
jump into an async context. This will allow us later on to create a
connection to Discord, 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.
### 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)]
### 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!** 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.
>[!NOTE]
Connection logic is incomplete as of the current build. Events will
soon be added to indicate when the client's state is ready for use;
(rewrite this section when possible)
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 [installing guide]
for how to fix this.
[TAP]: https://docs.microsoft.com/en-us/dotnet/articles/csharp/async
[API Documentation]: xref:Discord.Rest.BaseDiscordClient#Discord_Rest_BaseDiscordClient_Log
[DiscordSocketClient]: xref:Discord.WebSocket.DiscordSocketClient
[installing guide]: installing.md#installing-on-net-standard-11
### Handling a 'ping'
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 in to
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 came - `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 bot that will be carrying out multiple
commands, it is strongly encouraged 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.SocketMessageChannel
[completed program]: samples/intro/complete.cs
# Building a bot with commands
This section will show you how to write a program that is ready for
[commands](commands.md). Note that this 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

View File

@@ -0,0 +1,15 @@
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()
{
}
}
}

View File

@@ -0,0 +1,16 @@
// Program.cs
using Discord.WebSocket;
// ...
public async Task MainAsync()
{
var 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);
}

View File

@@ -0,0 +1,42 @@
using Discord;
using Discord.WebSocket;
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()
{
var 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;
}
}
}

View File

@@ -0,0 +1,22 @@
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;
}
}
}

View File

@@ -0,0 +1,14 @@
public async Task MainAsync()
{
// client.Log ...
client.MessageReceived += MessageReceived;
// ...
}
private async Task MessageReceived(SocketMessage message)
{
if (message.Content == "!ping")
{
await message.Channel.SendMessageAsync("Pong!");
}
}

View File

@@ -0,0 +1,128 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
class Program
{
private readonly DiscordSocketClient _client;
// Keep the CommandService and IDependencyMap around for use with commands.
private readonly IDependencyMap _map = new DependencyMap();
private readonly CommandService _commands = new CommandService();
// 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 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), you should probably
// set the MessageCacheSize here.
//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
});
}
// Create a named logging handler, so it can be re-used by addons
// that ask for a Func<LogMessage, Task>.
private static Task Logger(LogMessage message)
{
var cc = Console.ForegroundColor;
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}");
Console.ForegroundColor = cc;
return Task.CompletedTask;
}
private async Task MainAsync()
{
// Subscribe the logging handler.
_client.Log += Logger;
// Centralize the logic for commands into a seperate 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(-1);
}
private async Task InitCommands()
{
// Repeat this for all the service classes
// and other dependencies that your commands might need.
_map.Add(new SomeServiceClass());
// Either search the program and add all Module classes that can be found:
await _commands.AddModulesAsync(Assembly.GetEntryAssembly());
// Or add Modules manually if you prefer to be a little more explicit:
await _commands.AddModuleAsync<SomeModule>();
// 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;
// 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(msg.Discord.CurrentUser, ref pos) */)
{
// Create a Command Context
var context = new SocketCommandContext(msg.Discord, msg);
// Execute the command. (result does not indicate a return value,
// rather an object stating if the command executed succesfully).
var result = await _commands.ExecuteAsync(context, pos, _map);
// Uncomment the following lines if you want the bot
// to send a message if it failed (not advised for most situations).
//if (!result.IsSuccess && result.Error != CommandError.UnknownCommand)
// await msg.Channel.SendMessageAsync(result.ErrorReason);
}
}
}

View File

@@ -0,0 +1,9 @@
using Discord.Providers.WS4Net;
using Discord.Providers.UDPClient;
using Discord.WebSocket;
// ...
var client = new DiscordSocketClient(new DiscordSocketConfig
{
WebSocketProvider = WS4NetProvider.Instance,
UdpSocketProvider = UDPClientProvider.Instance,
});

View File

@@ -0,0 +1,6 @@
<?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>

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Discord.Net" Version="1.0.0-rc-00617" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,38 @@
---
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 model 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`.