浏览代码

Cleanup FAQ trailing spaces

pull/988/head
Hsu Still 7 年前
父节点
当前提交
0dcb16119c
找不到此签名对应的密钥 GPG 密钥 ID: 8601A145FDA95209
共有 6 个文件被更改,包括 157 次插入153 次删除
  1. +50
    -50
      docs/faq/Commands.md
  2. +9
    -9
      docs/faq/Glossary.md
  3. +6
    -6
      docs/faq/Legacy.md
  4. +24
    -24
      docs/faq/basic-operations.md
  5. +24
    -23
      docs/faq/client-basics.md
  6. +44
    -41
      docs/faq/getting-started.md

+ 50
- 50
docs/faq/Commands.md 查看文件

@@ -2,17 +2,17 @@

## How can I restrict some of my commands so only certain users can execute them?

Based on how you want to implement the restrictions, you can use the
built-in [RequireUserPermission] precondition, which allows you to
restrict the command based on the user's current permissions in the
guild or channel (*e.g. `GuildPermission.Administrator`,
`ChannelPermission.ManageMessages` etc.*).
If, however, you wish to restrict the commands based on the user's
role, you can either create your own custom precondition or use
Joe4evr's [Preconditions Addons] that provides a few custom
preconditions that aren't provided in the stock library.
Its source can also be used as an example for creating your own
Based on how you want to implement the restrictions, you can use the
built-in [RequireUserPermission] precondition, which allows you to
restrict the command based on the user's current permissions in the
guild or channel (*e.g. `GuildPermission.Administrator`,
`ChannelPermission.ManageMessages` etc.*).
If, however, you wish to restrict the commands based on the user's
role, you can either create your own custom precondition or use
Joe4evr's [Preconditions Addons] that provides a few custom
preconditions that aren't provided in the stock library.
Its source can also be used as an example for creating your own
custom preconditions.

[RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute
@@ -20,8 +20,8 @@ custom preconditions.

## I'm getting an error about `Assembly#GetEntryAssembly`.

You may be confusing [CommandService#AddModulesAsync] with
[CommandService#AddModuleAsync]. The former is used to add modules
You may be confusing [CommandService#AddModulesAsync] with
[CommandService#AddModuleAsync]. The former is used to add modules
via the assembly, while the latter is used to add a single module.

[CommandService#AddModulesAsync]: xref:Discord.Commands.CommandService.AddModulesAsync*
@@ -29,10 +29,10 @@ via the assembly, while the latter is used to add a single module.

## What does [Remainder] do in the command signature?

The [RemainderAttribute] leaves the string unparsed, meaning you
don't have to add quotes around the text for the text to be
recognized as a single object. Please note that if your method has
multiple parameters, the remainder attribute can only be applied to
The [RemainderAttribute] leaves the string unparsed, meaning you
don't have to add quotes around the text for the text to be
recognized as a single object. Please note that if your method has
multiple parameters, the remainder attribute can only be applied to
the last parameter.

[!code-csharp[Remainder](samples/commands/Remainder.cs)]
@@ -41,17 +41,17 @@ the last parameter.

## What is a service? Why does my module not hold any data after execution?

In Discord.NET, modules are created similarly to ASP.NET, meaning
that they have a transient nature. This means that they are spawned
every time when a request is received, and are killed from memory
when the execution finishes. This is why you cannot store persistent
data inside a module. To workaround this, consider using a service.
Service is often used to hold data externally, so that they will
persist throughout execution. Think of it like a chest that holds
whatever you throw at it that won't be affected by anything unless
you want it to. Note that you should also learn Microsoft's
implementation of [Dependency Injection] \([video]) before proceeding, as well
In Discord.NET, modules are created similarly to ASP.NET, meaning
that they have a transient nature. This means that they are spawned
every time when a request is received, and are killed from memory
when the execution finishes. This is why you cannot store persistent
data inside a module. To workaround this, consider using a service.
Service is often used to hold data externally, so that they will
persist throughout execution. Think of it like a chest that holds
whatever you throw at it that won't be affected by anything unless
you want it to. Note that you should also learn Microsoft's
implementation of [Dependency Injection] \([video]) before proceeding, as well
as how it works in [Discord.NET](../guides/commands/commands.md#usage-in-modules).

A brief example of service and dependency injection can be seen below.
@@ -63,22 +63,22 @@ A brief example of service and dependency injection can be seen below.

## I have a long-running Task in my command, and Discord.NET keeps saying that a `MessageReceived` handler is blocking the gateway. What gives?

By default, all commands are executed on the same thread as the
gateway task, which is responsible for keeping the connection from
your client to Discord alive. By default, when you execute a command,
this blocks the gateway from communicating for as long as the command
task is being executed. The library will warn you about any long
running event handler (in this case, the command handler) that
persists for **more than 3 seconds**.
By default, all commands are executed on the same thread as the
gateway task, which is responsible for keeping the connection from
your client to Discord alive. By default, when you execute a command,
this blocks the gateway from communicating for as long as the command
task is being executed. The library will warn you about any long
running event handler (in this case, the command handler) that
persists for **more than 3 seconds**.

To resolve this, the library has designed a flag called [RunMode].
To resolve this, the library has designed a flag called [RunMode].

There are 2 main `RunMode`s.
1. `RunMode.Sync` (default)
1. `RunMode.Sync` (default)
2. `RunMode.Async`

You can set the `RunMode` either by specifying it individually via
the `CommandAttribute`, or by setting the global default with
the `CommandAttribute`, or by setting the global default with
the [DefaultRunMode] flag under `CommandServiceConfig`.

# [CommandAttribute](#tab/cmdattrib)
@@ -94,10 +94,10 @@ the [DefaultRunMode] flag under `CommandServiceConfig`.
***

> [!IMPORTANT]
> While specifying `RunMode.Async` allows the command to be spun off
> While specifying `RunMode.Async` allows the command to be spun off
> to a different thread instead of the gateway thread,
> keep in mind that there will be **potential consequences**
> by doing so. Before applying this flag, please
> keep in mind that there will be **potential consequences**
> by doing so. Before applying this flag, please
> consider whether it is necessary to do so.
>
> Further details regarding `RunMode.Async` can be found below.
@@ -108,28 +108,28 @@ the [DefaultRunMode] flag under `CommandServiceConfig`.

## How does `RunMode.Async` work, and why is Discord.NET *not* using it by default?

`RunMode.Async` works by spawning a new `Task` with an unawaited
[Task.Run], essentially making `ExecuteAsyncInternalAsync`, the task
that is used to invoke the command task, to be finished on a
`RunMode.Async` works by spawning a new `Task` with an unawaited
[Task.Run], essentially making `ExecuteAsyncInternalAsync`, the task
that is used to invoke the command task, to be finished on a
different thread. This means that [ExecuteAsync] will be forced to
return a successful [ExecuteResult] regardless of the execution.

The following are the known caveats with `RunMode.Async`,
1. You can potentially introduce race condition.
2. Unnecessary overhead caused by [async state machine].
3. [ExecuteAsync] will immediately return [ExecuteResult] instead of
other result types (this is particularly important for those who wish
3. [ExecuteAsync] will immediately return [ExecuteResult] instead of
other result types (this is particularly important for those who wish
to utilize [RuntimeResult] in 2.0).
4. Exceptions are swallowed.

However, there are ways to remedy some of these.

For #3, in Discord.NET 2.0, the library introduces a new event called
[CommandExecuted], which is raised whenever the command is
**successfully executed**. This event will be raised regardless of
For #3, in Discord.NET 2.0, the library introduces a new event called
[CommandExecuted], which is raised whenever the command is
**successfully executed**. This event will be raised regardless of
the `RunMode` type and will return the appropriate execution result.

For #4, exceptions are caught in [CommandService#Log] event under
For #4, exceptions are caught in [CommandService#Log] event under
[LogMessage.Exception] as [CommandException].

[Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run


+ 9
- 9
docs/faq/Glossary.md 查看文件

@@ -2,7 +2,7 @@

## Common Types

* A **Guild** ([IGuild]) is an isolated collection of users and
* A **Guild** ([IGuild]) is an isolated collection of users and
channels, and are often referred to as "servers".
- Example: [Discord API](https://discord.gg/jkrBmQR)
* A **Channel** ([IChannel]) represents either a voice or text channel.
@@ -14,11 +14,11 @@ channels, and are often referred to as "servers".
## Channel Types

### Message Channels
* A **Text channel** ([ITextChannel]) is a message channel from a
* A **Text channel** ([ITextChannel]) is a message channel from a
Guild.
* A **DM channel** ([IDMChannel]) is a message channel from a DM.
* A **Group channel** ([IGroupChannel]) is a message channel from a
Group.
* A **Group channel** ([IGroupChannel]) is a message channel from a
Group.
- This is rarely used due to the bot's inability to join groups.
* A **Private channel** ([IPrivateChannel]) is a DM or a Group.
* A **Message channel** ([IMessageChannel]) can be any of the above.
@@ -27,7 +27,7 @@ Group.
* A **Guild channel** ([IGuildChannel]) is a guild channel in a guild.
- This can be any channels that may exist in a guild.
* A **Voice channel** ([IVoiceChannel]) is a voice channel in a guild.
* A **Category channel** ([ICategoryChannel]) (2.0+) is a category that
* A **Category channel** ([ICategoryChannel]) (2.0+) is a category that
holds one or more sub-channels.

[IGuildChannel]: xref:Discord.IGuildChannel
@@ -52,12 +52,12 @@ holds one or more sub-channels.
## Activity Types

* A **Game** ([Game]) refers to a user's game activity.
* A **Rich Presence** ([RichGame]) refers to a user's detailed
gameplay status.
* A **Rich Presence** ([RichGame]) refers to a user's detailed
gameplay status.
- Visit [Rich Presence Intro] on Discord docs for more info.
* A **Streaming Status** ([StreamingGame]) refers to user's activity
* A **Streaming Status** ([StreamingGame]) refers to user's activity
for streaming on services such as Twitch.
* A **Spotify Status** ([SpotifyGame]) (2.0+) refers to a user's
* A **Spotify Status** ([SpotifyGame]) (2.0+) refers to a user's
activity for listening to a song on Spotify.

[Game]: xref:Discord.Game


+ 6
- 6
docs/faq/Legacy.md 查看文件

@@ -1,10 +1,10 @@
# Legacy Questions

## X, Y, Z does not work! It doesn't return a valid value anymore.
If you're currently using an older version in stable branch, please
upgrade to the latest pre-release version to ensure maximum
compatibility. Several features may be broken in older
versions and will likely not be fixed in the version branch due to
If you're currently using an older version in stable branch, please
upgrade to the latest pre-release version to ensure maximum
compatibility. Several features may be broken in older
versions and will likely not be fixed in the version branch due to
their breaking nature.

Visit the repo's [release tag] to see the latest public pre-release.
@@ -12,8 +12,8 @@ Visit the repo's [release tag] to see the latest public pre-release.
[release tag]: https://github.com/RogueException/Discord.Net/releases

## I came from an earlier version of Discord.NET 1.0, and DependencyMap doesn't seem to exist anymore in the later revision? What happened to it?
The `DependencyMap` has been replaced with Microsoft's
[DependencyInjection] Abstractions. An example usage can be seen
The `DependencyMap` has been replaced with Microsoft's
[DependencyInjection] Abstractions. An example usage can be seen
[here](https://github.com/foxbot/DiscordBotBase/blob/csharp/src/DiscordBot/Program.cs#L36).

[DependencyInjection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection

+ 24
- 24
docs/faq/basic-operations.md 查看文件

@@ -3,15 +3,15 @@
## How should I safely check a type?

> [!WARNING]
> Direct casting (e.g. `(Type)type`) is **the least recommended**
> way of casting, as it *can* throw an [InvalidCastException]
> Direct casting (e.g. `(Type)type`) is **the least recommended**
> way of casting, as it *can* throw an [InvalidCastException]
> when the object isn't the desired type.
>
> Please refer to [this post] for more details.

In Discord.NET, the idea of polymorphism is used throughout. You may
need to cast the object as a certain type before you can perform any
action.
In Discord.NET, the idea of polymorphism is used throughout. You may
need to cast the object as a certain type before you can perform any
action.

A good and safe casting example:

@@ -25,15 +25,15 @@ A good and safe casting example:
> [!TIP]
> The [GetChannel] method by default returns an [IChannel].
> This means channels such as [IVoiceChannel], [ICategoryChannel]
> can be returned. This is why that you cannot send message
> can be returned. This is why that you cannot send message
> to channels like those.

Any implementation of [IMessageChannel] has a [SendMessageAsync]
method. You can get the channel via [GetChannel] under the client.
Remember, when using Discord.NET, polymorphism is a common recurring
theme. This means an object may take in many shapes or form, which
means casting is your friend. You should attempt to cast the channel
as an [IMessageChannel] or any other entity that implements it to be
Remember, when using Discord.NET, polymorphism is a common recurring
theme. This means an object may take in many shapes or form, which
means casting is your friend. You should attempt to cast the channel
as an [IMessageChannel] or any other entity that implements it to be
able to message.

[SendMessageAsync]: xref:Discord.IMessageChannel.SendMessageAsync*
@@ -41,7 +41,7 @@ able to message.

## How can I tell if a message is from X, Y, Z channel?

You may check the message channel type. Visit [Glossary] to see the
You may check the message channel type. Visit [Glossary] to see the
various types of channels.

[Glossary]: Glossary.md#message-channels
@@ -50,13 +50,13 @@ various types of channels.

There are 2 ways to do this. You can do either of the following,
1. Cast the user as an [IGuildUser] and use its [IGuild] property.
2. Cast the channel as an [IGuildChannel] and use
2. Cast the channel as an [IGuildChannel] and use
its [IGuild] property.

## How do I add hyperlink text to an embed?

Embeds can use standard [markdown] in the description field as well
as in field values. With that in mind, links can be added with
Embeds can use standard [markdown] in the description field as well
as in field values. With that in mind, links can be added with
`[text](link)`.

[markdown]: https://support.discordapp.com/hc/en-us/articles/210298617-Markdown-Text-101-Chat-Formatting-Bold-Italic-Underline-
@@ -64,26 +64,26 @@ as in field values. With that in mind, links can be added with
## How do I add reactions to a message?

Any entities that implement [IUserMessage] has an [AddReactionAsync]
method. This method expects an [IEmote] as a parameter.
In Discord.Net, an Emote represents a server custom emote, while an
Emoji is a Unicode emoji (standard emoji). Both [Emoji] and [Emote]
implement [IEmote] and are valid options.
method. This method expects an [IEmote] as a parameter.
In Discord.Net, an Emote represents a server custom emote, while an
Emoji is a Unicode emoji (standard emoji). Both [Emoji] and [Emote]
implement [IEmote] and are valid options.

[!code-csharp[Emoji](samples/basics/emoji.cs)]

[AddReactionAsync]: xref:Discord.IUserMessage.AddReactionAsync*
## Why am I getting so many preemptive rate limits when I try to add more than one reactions?

This is due to how HTML header works, mistreating
0.25sec/action to 1sec. This casues the lib to throw preemptive rate
limit more frequently than it should for methods such as adding
This is due to how HTML header works, mistreating
0.25sec/action to 1sec. This casues the lib to throw preemptive rate
limit more frequently than it should for methods such as adding
reactions.

## Can I opt-out of preemptive rate limits?
Unfortunately, not at the moment. See [#401](https://github.com/RogueException/Discord.Net/issues/401).

[IChannel]: xref:Discord.IChannel
[ICategoryChannel]: xref:Discord.ICategoryChannel


+ 24
- 23
docs/faq/client-basics.md 查看文件

@@ -3,35 +3,35 @@
## My client keeps returning 401 upon logging in!

> [!WARNING]
> Userbot/selfbot (logging in with a user token) is not
> Userbot/selfbot (logging in with a user token) is not
> officially supported with this library.
>
> Logging in under a user account may result in account
> Logging in under a user account may result in account
> termination!

There are few possible reasons why this may occur.
1. You are not using the appropriate [TokenType].
If you are using a bot account created from the Discord Developer
portal, you should be using `TokenType.Bot`.
2. You are not using the correct login credentials.
Please keep in mind that tokens start with `Mj*`.
If it starts with any other characters, chances are, you might be
using the *client secret*, which has nothing to do with the login
1. You are not using the appropriate [TokenType].
If you are using a bot account created from the Discord Developer
portal, you should be using `TokenType.Bot`.
2. You are not using the correct login credentials.
Please keep in mind that tokens start with `Mj*`.
If it starts with any other characters, chances are, you might be
using the *client secret*, which has nothing to do with the login
token.

[TokenType]: xref:Discord.TokenType

## How do I do X, Y, Z when my bot connects/logs on? Why do I get a `NullReferenceException` upon calling any client methods after connect?

Your bot should **not** attempt to interact in any way with
guilds/servers until the [Ready] event fires. When the bot
connects, it first has to download guild information from
Discord in order for you to get access to any server
information; the client is not ready at this point.
Technically, the [GuildAvailable] event fires once the data for a
particular guild has downloaded; however, it's best to wait for all
guilds to be downloaded. Once all downloads are complete, the [Ready]
Your bot should **not** attempt to interact in any way with
guilds/servers until the [Ready] event fires. When the bot
connects, it first has to download guild information from
Discord in order for you to get access to any server
information; the client is not ready at this point.
Technically, the [GuildAvailable] event fires once the data for a
particular guild has downloaded; however, it's best to wait for all
guilds to be downloaded. Once all downloads are complete, the [Ready]
event is triggered, then you can proceed to do whatever you like.

[Ready]: xref:Discord.WebSocket.DiscordSocketClient.Ready
@@ -39,14 +39,15 @@ event is triggered, then you can proceed to do whatever you like.

## How do I get a message's previous content when that message is edited?

If you need to do anything with messages (e.g. checking Reactions,
checking the content of edited/deleted messages), you must set the
[MessageCacheSize] in your [DiscordSocketConfig] settings in order to
If you need to do anything with messages (e.g. checking Reactions,
checking the content of edited/deleted messages), you must set the
[MessageCacheSize] in your [DiscordSocketConfig] settings in order to
use the cached message entity. Read more about it [here](../guides/concepts/events.md#cacheable).

1. Message Cache must be enabled.
2. Hook the MessageUpdated event. This event provides a *before* and
2. Hook the MessageUpdated event. This event provides a *before* and
*after* object.
3. Only messages received *after* the bot comes online will be
3. Only messages received *after* the bot comes online will be
available in the cache.

[MessageCacheSize]: xref:Discord.WebSocket.DiscordSocketConfig.MessageCacheSize


+ 44
- 41
docs/faq/getting-started.md 查看文件

@@ -1,81 +1,84 @@
# Basic Concepts / Getting Started

## How do I get started?
First of all, welcome! You may visit us on our Discord should you
have any questions. Before you delve into using the library,
however, you should have some decent understanding of the language
you are about to use. This library touches on
[Task-based Asynchronous Pattern] \(TAP), [polymorphism], [interface]
and many more advanced topics extensively. Please make sure that you

First of all, welcome! You may visit us on our Discord should you
have any questions. Before you delve into using the library,
however, you should have some decent understanding of the language
you are about to use. This library touches on
[Task-based Asynchronous Pattern] \(TAP), [polymorphism], [interface]
and many more advanced topics extensively. Please make sure that you
understand these topics to some extent before proceeding.
Here are some examples:
1. [Official quick start guide](https://github.com/RogueException/Discord.Net/blob/dev/docs/guides/getting_started/samples/intro/structure.cs)
2. [Official template](https://github.com/foxbot/DiscordBotBase/tree/csharp/src/DiscordBot)

> [!TIP]
> Please note that you should *not* try to blindly copy paste
> the code. The examples are meant to be a template or a guide.
> [!TIP]
> Please note that you should *not* try to blindly copy paste
> the code. The examples are meant to be a template or a guide.
> It is not meant to be something that will work out of the box.
[Task-based Asynchronous Pattern]: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap
[polymorphism]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism
[interface]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/
## How do I add my bot to my server/guild?

You can do so by using the [permission calculator] provided
You can do so by using the [permission calculator] provided
by FiniteReality.
This tool allows you to set the permissions that the bot will be
added with, and invite the bot into your guild. With this method,
bots will also be assigned their own special roles that normal users
This tool allows you to set the permissions that the bot will be
added with, and invite the bot into your guild. With this method,
bots will also be assigned their own special roles that normal users
cannot use; this is what we call a `Managed` role, and this is a much
safer method of permission management than to create a role that any
safer method of permission management than to create a role that any
users can be assigned to.

[permission calculator]: https://finitereality.github.io/permissions-calculator

## What is a Client/User/Object ID? Is it the token?

Each user and object on Discord has its own snowflake ID generated
Each user and object on Discord has its own snowflake ID generated
based on various conditions.
![Snowflake Generation](images/snowflake.png)
The ID can be seen by anyone; it is public. It is merely used to
identify an object in the Discord ecosystem. Many things in the
library require an ID to retrieve the said object.
There are 2 ways to obtain the said ID.
1. Enable Discord's developer mode. With developer mode enabled,
you can - as an example - right click on a guild and copy the guild
id (please note that this does not apply to all objects, such as
The ID can be seen by anyone; it is public. It is merely used to
identify an object in the Discord ecosystem. Many things in the
library require an ID to retrieve the said object.

There are 2 ways to obtain the said ID.

1. Enable Discord's developer mode. With developer mode enabled,
you can - as an example - right click on a guild and copy the guild
id (please note that this does not apply to all objects, such as
Role IDs \[see below], or DM channel IDs).
![Developer Mode](images/dev-mode.png)
2. Escape the object using `\` in front the object. For example,
when you do `\@Example#1234` in chat, it will return the user ID of
2. Escape the object using `\` in front the object. For example,
when you do `\@Example#1234` in chat, it will return the user ID of
the aforementioned user.
A token is a credential used to log into an account. This information
should be kept **private** and for your eyes only. Anyone with your
token can log into your account. This applies to both user and bot
accounts. That also means that you should never ever hardcode your
token or add it into source control, as your identity may be stolen
by scrape bots on the internet that scours through constantly to
A token is a credential used to log into an account. This information
should be kept **private** and for your eyes only. Anyone with your
token can log into your account. This applies to both user and bot
accounts. That also means that you should never ever hardcode your
token or add it into source control, as your identity may be stolen
by scrape bots on the internet that scours through constantly to
obtain a token.

## How do I get the role ID?

Several common ways to do this:
1. Make the role mentionable and mention the role, and escape it

1. Make the role mentionable and mention the role, and escape it
using the `\` character in front.
2. Inspect the roles collection within the guild via your debugger.
Please note that right-clicking on the role and copying the ID will
Please note that right-clicking on the role and copying the ID will
**not** work. It will only copy the message ID.

## I have more questions!
## I have more questions!

Please visit us at #dotnet_discord-net at [Discord API].
Describe the problem in details to us, and preferably with the
Please visit us at #dotnet_discord-net at [Discord API].
Describe the problem in details to us, and preferably with the
problematic code uploaded onto [Hastebin](https://hastebin.com).

[Discord API]: https://discord.gg/jkrBmQR

正在加载...
取消
保存