FAQ rework, replacing outdated info, better interaction FAQ (#2106)
* FAQ rework, replacing outdated info, better interaction faq * Update docs/faq/basics/getting-started.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/faq/basics/getting-started.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * Update docs/faq/int_framework/general.md Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> * fix TOC reference Co-authored-by: Jared L <48422312+lhjt@users.noreply.github.com> Co-authored-by: Quin Lynch <lynchquin@gmail.com>
This commit is contained in:
142
docs/faq/text_commands/general.md
Normal file
142
docs/faq/text_commands/general.md
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
uid: FAQ.TextCommands.General
|
||||
title: General Questions about Text Commands
|
||||
---
|
||||
|
||||
# Chat Command-related Questions
|
||||
|
||||
In the following section, you will find commonly asked questions and
|
||||
answered regarding general command usage when using @Discord.Commands.
|
||||
|
||||
## How can I restrict some of my commands so only specific users can execute them?
|
||||
|
||||
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`*).
|
||||
|
||||
> [!NOTE]
|
||||
> There are many more preconditions to use, including being able to make some yourself.
|
||||
> Precondition documentation is covered [here](xref:Guides.TextCommands.Preconditions)
|
||||
|
||||
[RequireUserPermission]: xref:Discord.Commands.RequireUserPermissionAttribute
|
||||
|
||||
## Why am I getting an error about `Assembly.GetEntryAssembly`?
|
||||
|
||||
You may be confusing @Discord.Commands.CommandService.AddModulesAsync*
|
||||
with @Discord.Commands.CommandService.AddModuleAsync*. The former
|
||||
is used to add modules 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
|
||||
do not 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/Remainder.cs)]
|
||||
|
||||
[RemainderAttribute]: xref:Discord.Commands.RemainderAttribute
|
||||
|
||||
## Discord.Net keeps saying that a `MessageReceived` handler is blocking the gateway, what should I do?
|
||||
|
||||
By default, the library warns the user about any long-running event
|
||||
handler that persists for **more than 3 seconds**. Any event
|
||||
handlers that are run on the same thread as the gateway task, the task
|
||||
in charge of keeping the connection alive, may block the processing of
|
||||
heartbeat, and thus terminating the connection.
|
||||
|
||||
In this case, the library detects that a `MessageReceived`
|
||||
event handler is blocking the gateway thread. This warning is
|
||||
typically associated with the command handler as it listens for that
|
||||
particular event. If the command handler is blocking the thread, then
|
||||
this **might** mean that you have a long-running command.
|
||||
|
||||
> [!NOTE]
|
||||
> In rare cases, runtime errors can also cause blockage, usually
|
||||
> associated with Mono, which is not supported by this library.
|
||||
|
||||
To prevent a long-running command from blocking the gateway
|
||||
thread, a flag called [RunMode] is explicitly designed to resolve
|
||||
this issue.
|
||||
|
||||
There are 2 main `RunMode`s.
|
||||
|
||||
1. `RunMode.Sync`
|
||||
2. `RunMode.Async`
|
||||
|
||||
`Sync` is the default behavior and makes the command to be run on the
|
||||
same thread as the gateway one. `Async` will spin the task off to a
|
||||
different thread from the gateway one.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> While specifying `RunMode.Async` allows the command to be spun off
|
||||
> to a different thread, keep in mind that by doing so, there will be
|
||||
> **potentially unwanted consequences**. Before applying this flag,
|
||||
> please consider whether it is necessary to do so.
|
||||
>
|
||||
> Further details regarding `RunMode.Async` can be found below.
|
||||
|
||||
You can set the `RunMode` either by specifying it individually via
|
||||
the `CommandAttribute` or by setting the global default with
|
||||
the [DefaultRunMode] flag under `CommandServiceConfig`.
|
||||
|
||||
# [CommandAttribute](#tab/cmdattrib)
|
||||
|
||||
[!code-csharp[Command Attribute](samples/runmode-cmdattrib.cs)]
|
||||
|
||||
# [CommandServiceConfig](#tab/cmdconfig)
|
||||
|
||||
[!code-csharp[Command Service Config](samples/runmode-cmdconfig.cs)]
|
||||
|
||||
***
|
||||
|
||||
***
|
||||
|
||||
[RunMode]: xref:Discord.Commands.RunMode
|
||||
[CommandAttribute]: xref:Discord.Commands.CommandAttribute
|
||||
[DefaultRunMode]: xref:Discord.Commands.CommandServiceConfig.DefaultRunMode
|
||||
|
||||
## 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 the task that is used to invoke the
|
||||
command task to be finished on a different thread. This design means
|
||||
that [ExecuteAsync] will be forced to return a successful
|
||||
[ExecuteResult] regardless of the actual execution result.
|
||||
|
||||
The following are the known caveats with `RunMode.Async`,
|
||||
|
||||
1. You can potentially introduce a race condition.
|
||||
2. Unnecessary overhead caused by the [async state machine].
|
||||
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 in the `ExecuteAsync` result.
|
||||
|
||||
However, there are ways to remedy some of these.
|
||||
|
||||
For #3, in Discord.Net 2.0, the library introduces a new event called
|
||||
[CommandService.CommandExecuted], which is raised whenever the command is executed.
|
||||
This event will be raised regardless of
|
||||
the `RunMode` type and will return the appropriate execution result
|
||||
and the associated @Discord.Commands.CommandInfo if applicable.
|
||||
|
||||
For #4, exceptions are caught in [CommandService.Log] event under
|
||||
[LogMessage.Exception] as [CommandException] and in the
|
||||
[CommandService.CommandExecuted] event under the [IResult] as
|
||||
[ExecuteResult.Exception].
|
||||
|
||||
[Task.Run]: https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.run
|
||||
[async state machine]: https://www.red-gate.com/simple-talk/dotnet/net-tools/c-async-what-is-it-and-how-does-it-work/
|
||||
[ExecuteAsync]: xref:Discord.Commands.CommandService.ExecuteAsync*
|
||||
[ExecuteResult]: xref:Discord.Commands.ExecuteResult
|
||||
[RuntimeResult]: xref:Discord.Commands.RuntimeResult
|
||||
[CommandService.CommandExecuted]: xref:Discord.Commands.CommandService.CommandExecuted
|
||||
[CommandService.Log]: xref:Discord.Commands.CommandService.Log
|
||||
[LogMessage.Exception]: xref:Discord.LogMessage.Exception*
|
||||
[ExecuteResult.Exception]: xref:Discord.Commands.ExecuteResult.Exception*
|
||||
[CommandException]: xref:Discord.Commands.CommandException
|
||||
[IResult]: xref:Discord.Commands.IResult
|
||||
20
docs/faq/text_commands/samples/Remainder.cs
Normal file
20
docs/faq/text_commands/samples/Remainder.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Input:
|
||||
// !echo Coffee Cake
|
||||
|
||||
// Output:
|
||||
// Coffee Cake
|
||||
[Command("echo")]
|
||||
public Task EchoRemainderAsync([Remainder]string text) => ReplyAsync(text);
|
||||
|
||||
// Output:
|
||||
// CommandError.BadArgCount
|
||||
[Command("echo-hassle")]
|
||||
public Task EchoAsync(string text) => ReplyAsync(text);
|
||||
|
||||
// The message would be seen as having multiple parameters,
|
||||
// while the method only accepts one.
|
||||
// Wrapping the message in quotes solves this.
|
||||
// This way, the system knows the entire message is to be parsed as a
|
||||
// single String.
|
||||
// e.g.,
|
||||
// !echo "Coffee Cake"
|
||||
7
docs/faq/text_commands/samples/runmode-cmdattrib.cs
Normal file
7
docs/faq/text_commands/samples/runmode-cmdattrib.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
[Command("process", RunMode = RunMode.Async)]
|
||||
public async Task ProcessAsync(string input)
|
||||
{
|
||||
// Does heavy calculation here.
|
||||
await Task.Delay(TimeSpan.FromMinute(1));
|
||||
await ReplyAsync(input);
|
||||
}
|
||||
10
docs/faq/text_commands/samples/runmode-cmdconfig.cs
Normal file
10
docs/faq/text_commands/samples/runmode-cmdconfig.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
public class Setup
|
||||
{
|
||||
private readonly CommandService _command;
|
||||
|
||||
public Setup()
|
||||
{
|
||||
var config = new CommandServiceConfig{ DefaultRunMode = RunMode.Async };
|
||||
_command = new CommandService(config);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user