docs: Main docs update (#1304)
* Remove template in favor of official samples * Fixed a variable name copy pasta mistake line 35 was _database.GetData() instead of DBService.GetData() * Experimental theme change * Change paragraph, code, heading fonts * Widen viewport * Update DocFX.Plugins.LastModified v1.2.3 * Exclude Discord.API in docs * Add remarks for SocketReaction properties * Add examples for BaseSocketClient.Events * Add additional clarification for some methods * Move IUser and IGuildChannel examples * Clarify several guides samples with notes - Reword TypeReader comment to avoid giving the idea that the sample itself is "obsolete" - Remove CommandException logging comment regarding C#7.0 as the version is now the standard across VS2017 and up - Remove suggestion about handling result in command handler since it is now advised to use CommandExecuted instead + Add additional comment to clarify ctor for DI setup * Add/migrate code examples * Incorporate material design theme License @ https://github.com/ovasquez * Update installation and nightly guide * Fix improper indentations made obvious by the widen viewport * Fix minor grammar issues + Add installation for nightly build using dotnet CLI * Fix nav level indentation * Revise "Your First Bot" article * Merge some paragraphs to avoid clutter while keeping readability * Reword the use of command framework + Add additional warning/note about environment variable * Add additional indent level * Fix indentation text warping * Remove connections sample * Update logging sample Remove redundant part of the sample * Remove mention of RPC * Remove misleading section about commands - Remove command sample from complete snippet * Revise "Your First Bot" command paragraphs * Change wording to hint devs that additional command parser packages may be available, as more and more begin to crop up * Update themes * Add XML docs contribution guidelines Update guidelines * Update CommandExecuted remarks * Fix precondition remarks typo no one saw that ok * Fix permission sample in docfx * Fix IMessageChannel samples * Update docs/_template/light-dark-theme/styles/docfx.vendor.minify.css Co-Authored-By: Still34 <341464@gmail.com> * Update docs/_template/light-dark-theme/styles/material.css Co-Authored-By: Still34 <341464@gmail.com> * Update docs/_template/light-dark-theme/styles/material.css Co-Authored-By: Still34 <341464@gmail.com>
This commit is contained in:
@@ -39,15 +39,8 @@ namespace Discord.Commands
|
||||
/// Occurs when a command is successfully executed without any error.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This event is fired when a command has been successfully executed without any of the following errors:
|
||||
/// </para>
|
||||
/// <para>* Parsing error</para>
|
||||
/// <para>* Precondition error</para>
|
||||
/// <para>* Runtime exception</para>
|
||||
/// <para>
|
||||
/// Should the command encounter any of the aforementioned error, this event will not be raised.
|
||||
/// </para>
|
||||
/// This event is fired when a command has been executed, successfully or not. When a command fails to
|
||||
/// execute during parsing or precondition stage, the CommandInfo may not be returned.
|
||||
/// </remarks>
|
||||
public event Func<Optional<CommandInfo>, ICommandContext, IResult, Task> CommandExecuted { add { _commandExecutedEvent.Add(value); } remove { _commandExecutedEvent.Remove(value); } }
|
||||
internal readonly AsyncEvent<Func<Optional<CommandInfo>, ICommandContext, IResult, Task>> _commandExecutedEvent = new AsyncEvent<Func<Optional<CommandInfo>, ICommandContext, IResult, Task>>();
|
||||
|
||||
@@ -97,26 +97,12 @@ namespace Discord
|
||||
/// Adds or updates the permission overwrite for the given role.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example fetches a role via <see cref="IGuild.GetRole"/> and a channel via
|
||||
/// <para>The following example fetches a role via <see cref="IGuild.GetRole"/> and a channel via
|
||||
/// <see cref="IGuild.GetChannelAsync"/>. Next, it checks if an overwrite had already been set via
|
||||
/// <see cref="GetPermissionOverwrite(Discord.IRole)"/>; if not, it denies the role from sending any
|
||||
/// messages to the channel.
|
||||
/// <code lang="cs">
|
||||
/// // Fetches the role and channels
|
||||
/// var role = guild.GetRole(339805618376540160);
|
||||
/// var channel = await guild.GetChannelAsync(233937283911385098);
|
||||
///
|
||||
/// // If either the of the object does not exist, bail
|
||||
/// if (role == null || channel == null) return;
|
||||
///
|
||||
/// // Fetches the previous overwrite and bail if one is found
|
||||
/// var previousOverwrite = channel.GetPermissionOverwrite(role);
|
||||
/// if (previousOverwrite.HasValue) return;
|
||||
///
|
||||
/// // Creates a new OverwritePermissions with send message set to deny and pass it into the method
|
||||
/// await channel.AddPermissionOverwriteAsync(role,
|
||||
/// new OverwritePermissions(sendMessage: PermValue.Deny));
|
||||
/// </code>
|
||||
/// messages to the channel.</para>
|
||||
/// <code language="cs" region="AddPermissionOverwriteAsyncRole"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IGuildChannel.Examples.cs"/>
|
||||
/// </example>
|
||||
/// <param name="role">The role to add the overwrite to.</param>
|
||||
/// <param name="permissions">The overwrite to add to the role.</param>
|
||||
@@ -130,26 +116,12 @@ namespace Discord
|
||||
/// Adds or updates the permission overwrite for the given user.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example fetches a user via <see cref="IGuild.GetUserAsync"/> and a channel via
|
||||
/// <para>The following example fetches a user via <see cref="IGuild.GetUserAsync"/> and a channel via
|
||||
/// <see cref="IGuild.GetChannelAsync"/>. Next, it checks if an overwrite had already been set via
|
||||
/// <see cref="GetPermissionOverwrite(Discord.IUser)"/>; if not, it denies the user from sending any
|
||||
/// messages to the channel.
|
||||
/// <code lang="cs">
|
||||
/// // Fetches the role and channels
|
||||
/// var user = await guild.GetUserAsync(168693960628371456);
|
||||
/// var channel = await guild.GetChannelAsync(233937283911385098);
|
||||
///
|
||||
/// // If either the of the object does not exist, bail
|
||||
/// if (user == null || channel == null) return;
|
||||
///
|
||||
/// // Fetches the previous overwrite and bail if one is found
|
||||
/// var previousOverwrite = channel.GetPermissionOverwrite(user);
|
||||
/// if (previousOverwrite.HasValue) return;
|
||||
///
|
||||
/// // Creates a new OverwritePermissions with send message set to deny and pass it into the method
|
||||
/// await channel.AddPermissionOverwriteAsync(role,
|
||||
/// new OverwritePermissions(sendMessage: PermValue.Deny));
|
||||
/// </code>
|
||||
/// messages to the channel.</para>
|
||||
/// <code language="cs" region="AddPermissionOverwriteAsyncUser"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IGuildChannel.Examples.cs"/>
|
||||
/// </example>
|
||||
/// <param name="user">The user to add the overwrite to.</param>
|
||||
/// <param name="permissions">The overwrite to add to the user.</param>
|
||||
|
||||
@@ -14,13 +14,10 @@ namespace Discord
|
||||
/// Sends a message to this message channel.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example sends a message with the current system time in RFC 1123 format to the channel and
|
||||
/// deletes itself after 5 seconds.
|
||||
/// <code language="cs">
|
||||
/// var message = await channel.SendMessageAsync(DateTimeOffset.UtcNow.ToString("R"));
|
||||
/// await Task.Delay(TimeSpan.FromSeconds(5))
|
||||
/// .ContinueWith(x => message.DeleteAsync());
|
||||
/// </code>
|
||||
/// <para>The following example sends a message with the current system time in RFC 1123 format to the channel and
|
||||
/// deletes itself after 5 seconds.</para>
|
||||
/// <code language="cs" region="SendMessageAsync"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// </example>
|
||||
/// <param name="text">The message to be sent.</param>
|
||||
/// <param name="isTTS">Determines whether the message should be read aloud by Discord or not.</param>
|
||||
@@ -35,18 +32,14 @@ namespace Discord
|
||||
/// Sends a file to this message channel with an optional caption.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example uploads a local file called <c>wumpus.txt</c> along with the text
|
||||
/// <c>good discord boi</c> to the channel.
|
||||
/// <code language="cs">
|
||||
/// await channel.SendFileAsync("wumpus.txt", "good discord boi");
|
||||
/// </code>
|
||||
///
|
||||
/// The following example uploads a local image called <c>b1nzy.jpg</c> embedded inside a rich embed to the
|
||||
/// channel.
|
||||
/// <code language="cs">
|
||||
/// await channel.SendFileAsync("b1nzy.jpg",
|
||||
/// embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
|
||||
/// </code>
|
||||
/// <para>The following example uploads a local file called <c>wumpus.txt</c> along with the text
|
||||
/// <c>good discord boi</c> to the channel.</para>
|
||||
/// <code language="cs" region="SendFileAsync.FilePath"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// <para>The following example uploads a local image called <c>b1nzy.jpg</c> embedded inside a rich embed to the
|
||||
/// channel.</para>
|
||||
/// <code language="cs" region="SendFileAsync.FilePath.EmbeddedImage"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// This method sends a file as if you are uploading an attachment directly from your Discord client.
|
||||
@@ -70,12 +63,10 @@ namespace Discord
|
||||
/// Sends a file to this message channel with an optional caption.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example uploads a streamed image that will be called <c>b1nzy.jpg</c> embedded inside a
|
||||
/// rich embed to the channel.
|
||||
/// <code language="cs">
|
||||
/// await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg",
|
||||
/// embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
|
||||
/// </code>
|
||||
/// <para>The following example uploads a streamed image that will be called <c>b1nzy.jpg</c> embedded inside a
|
||||
/// rich embed to the channel.</para>
|
||||
/// <code language="cs" region="SendFileAsync.FileStream.EmbeddedImage"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// </example>
|
||||
/// <remarks>
|
||||
/// This method sends a file as if you are uploading an attachment directly from your Discord client.
|
||||
@@ -130,12 +121,10 @@ namespace Discord
|
||||
/// of flattening.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example downloads 300 messages and gets messages that belong to the user
|
||||
/// <c>53905483156684800</c>.
|
||||
/// <code lang="cs">
|
||||
/// var messages = await messageChannel.GetMessagesAsync(300).FlattenAsync();
|
||||
/// var userMessages = messages.Where(x => x.Author.Id == 53905483156684800);
|
||||
/// </code>
|
||||
/// <para>The following example downloads 300 messages and gets messages that belong to the user
|
||||
/// <c>53905483156684800</c>.</para>
|
||||
/// <code language="cs" region="GetMessagesAsync.FromLimit.Standard"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// </example>
|
||||
/// <param name="limit">The numbers of message to be gotten from.</param>
|
||||
/// <param name="mode">The <see cref="CacheMode" /> that determines whether the object should be fetched from
|
||||
@@ -168,10 +157,13 @@ namespace Discord
|
||||
/// of flattening.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example gets 5 message prior to the message identifier <c>442012544660537354</c>.
|
||||
/// <code lang="cs">
|
||||
/// var messages = await channel.GetMessagesAsync(442012544660537354, Direction.Before, 5).FlattenAsync();
|
||||
/// </code>
|
||||
/// <para>The following example gets 5 message prior to the message identifier <c>442012544660537354</c>.</para>
|
||||
/// <code language="cs" region="GetMessagesAsync.FromId.FromMessage"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// <para>The following example attempts to retrieve <c>messageCount</c> number of messages from the
|
||||
/// beginning of the channel and prints them to the console.</para>
|
||||
/// <code language="cs" region="GetMessagesAsync.FromId.BeginningMessages"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// </example>
|
||||
/// <param name="fromMessageId">The ID of the starting message to get the messages from.</param>
|
||||
/// <param name="dir">The direction of the messages to be gotten from.</param>
|
||||
@@ -206,10 +198,9 @@ namespace Discord
|
||||
/// of flattening.
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example gets 5 message prior to a specific message, <c>oldMessage</c>.
|
||||
/// <code lang="cs">
|
||||
/// var messages = await channel.GetMessagesAsync(oldMessage, Direction.Before, 5).FlattenAsync();
|
||||
/// </code>
|
||||
/// <para>The following example gets 5 message prior to a specific message, <c>oldMessage</c>.</para>
|
||||
/// <code language="cs" region="GetMessagesAsync.FromMessage"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// </example>
|
||||
/// <param name="fromMessage">The starting message to get the messages from.</param>
|
||||
/// <param name="dir">The direction of the messages to be gotten from.</param>
|
||||
@@ -262,13 +253,9 @@ namespace Discord
|
||||
/// object is disposed.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example keeps the client in the typing state until <c>LongRunningAsync</c> has finished.
|
||||
/// <code lang="cs">
|
||||
/// using (messageChannel.EnterTypingState())
|
||||
/// {
|
||||
/// await LongRunningAsync();
|
||||
/// }
|
||||
/// </code>
|
||||
/// <para>The following example keeps the client in the typing state until <c>LongRunningAsync</c> has finished.</para>
|
||||
/// <code language="cs" region="EnterTypingState"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Channels\IMessageChannel.Examples.cs" />
|
||||
/// </example>
|
||||
/// <param name="options">The options to be used when sending the request.</param>
|
||||
/// <returns>
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Discord
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example gets 250 messages from the channel and deletes them.
|
||||
/// <code lang="cs">
|
||||
/// <code language="cs">
|
||||
/// var messages = await textChannel.GetMessagesAsync(250).FlattenAsync();
|
||||
/// await textChannel.DeleteMessagesAsync(messages);
|
||||
/// </code>
|
||||
|
||||
@@ -440,16 +440,8 @@ namespace Discord
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example creates a new text channel under an existing category named <c>Wumpus</c> with a set topic.
|
||||
/// <code lang="cs">
|
||||
/// var categories = await guild.GetCategoriesAsync();
|
||||
/// var targetCategory = categories.FirstOrDefault(x => x.Name == "wumpus");
|
||||
/// if (targetCategory == null) return;
|
||||
/// await Context.Guild.CreateTextChannelAsync(name, x =>
|
||||
/// {
|
||||
/// x.CategoryId = targetCategory.Id;
|
||||
/// x.Topic = $"This channel was created at {DateTimeOffset.UtcNow} by {user}.";
|
||||
/// });
|
||||
/// </code>
|
||||
/// <code language="cs" region="CreateTextChannelAsync"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Guilds\IGuild.Examples.cs"/>
|
||||
/// </example>
|
||||
/// <param name="name">The new name for the text channel.</param>
|
||||
/// <param name="func">The delegate containing the properties to be applied to the channel upon its creation.</param>
|
||||
|
||||
@@ -23,10 +23,8 @@ namespace Discord
|
||||
/// <example>
|
||||
/// The following example attempts to retrieve the user's current avatar and send it to a channel; if one is
|
||||
/// not set, a default avatar for this user will be returned instead.
|
||||
/// <code language="cs">
|
||||
/// var userAvatarUrl = user.GetAvatarUrl() ?? user.GetDefaultAvatarUrl();
|
||||
/// await textChannel.SendMessageAsync(userAvatarUrl);
|
||||
/// </code>
|
||||
/// <code language="cs" region="GetAvatarUrl"
|
||||
/// source="..\..\..\Discord.Net.Examples\Core\Entities\Users\IUser.Examples.cs"/>
|
||||
/// </example>
|
||||
/// <param name="format">The format to return.</param>
|
||||
/// <param name="size">The size of the image to return in. This can be any power of two between 16 and 2048.
|
||||
@@ -84,27 +82,18 @@ namespace Discord
|
||||
/// <remarks>
|
||||
/// This method is used to obtain or create a channel used to send a direct message.
|
||||
/// <note type="warning">
|
||||
/// In event that the current user cannot send a message to the target user, a channel can and will still be
|
||||
/// created by Discord. However, attempting to send a message will yield a
|
||||
/// <see cref="Discord.Net.HttpException"/> with a 403 as its
|
||||
/// <see cref="Discord.Net.HttpException.HttpCode"/>. There are currently no official workarounds by
|
||||
/// Discord.
|
||||
/// In event that the current user cannot send a message to the target user, a channel can and will
|
||||
/// still be created by Discord. However, attempting to send a message will yield a
|
||||
/// <see cref="Discord.Net.HttpException"/> with a 403 as its
|
||||
/// <see cref="Discord.Net.HttpException.HttpCode"/>. There are currently no official workarounds by
|
||||
/// Discord.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// The following example attempts to send a direct message to the target user and logs the incident should
|
||||
/// it fail.
|
||||
/// <code language="cs">
|
||||
/// var channel = await user.GetOrCreateDMChannelAsync();
|
||||
/// try
|
||||
/// {
|
||||
/// await channel.SendMessageAsync("Awesome stuff!");
|
||||
/// }
|
||||
/// catch (Discord.Net.HttpException ex) when (ex.HttpCode == 403)
|
||||
/// {
|
||||
/// Console.WriteLine($"Boo, I cannot message {user}");
|
||||
/// }
|
||||
/// </code>
|
||||
/// <code region="GetOrCreateDMChannelAsync" language="cs"
|
||||
/// source="../../../Discord.Net.Examples/Core/Entities/Users/IUser.Examples.cs"/>
|
||||
/// </example>
|
||||
/// <param name="options">The options to be used when sending the request.</param>
|
||||
/// <returns>
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace Discord
|
||||
/// Gets a generic channel.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code lang="cs" title="Example method">
|
||||
/// <code language="cs" title="Example method">
|
||||
/// var channel = await _client.GetChannelAsync(381889909113225237);
|
||||
/// if (channel != null && channel is IMessageChannel msgChannel)
|
||||
/// {
|
||||
@@ -194,7 +194,7 @@ namespace Discord
|
||||
/// Gets a user.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code lang="cs" title="Example method">
|
||||
/// <code language="cs" title="Example method">
|
||||
/// var user = await _client.GetUserAsync(168693960628371456);
|
||||
/// if (user != null)
|
||||
/// Console.WriteLine($"{user} is created at {user.CreatedAt}.";
|
||||
@@ -212,7 +212,7 @@ namespace Discord
|
||||
/// Gets a user.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code lang="cs" title="Example method">
|
||||
/// <code language="cs" title="Example method">
|
||||
/// var user = await _client.GetUserAsync("Still", "2876");
|
||||
/// if (user != null)
|
||||
/// Console.WriteLine($"{user} is created at {user.CreatedAt}.";
|
||||
@@ -232,7 +232,7 @@ namespace Discord
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example gets the most optimal voice region from the collection.
|
||||
/// <code lang="cs">
|
||||
/// <code language="cs">
|
||||
/// var regions = await client.GetVoiceRegionsAsync();
|
||||
/// var optimalRegion = regions.FirstOrDefault(x => x.IsOptimal);
|
||||
/// </code>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Discord.Net.Examples.Core.Entities.Channels
|
||||
{
|
||||
[PublicAPI]
|
||||
internal class GuildChannelExamples
|
||||
{
|
||||
#region AddPermissionOverwriteAsyncRole
|
||||
|
||||
public async Task MuteRoleAsync(IRole role, IGuildChannel channel)
|
||||
{
|
||||
if (role == null) throw new ArgumentNullException(nameof(role));
|
||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
// Fetches the previous overwrite and bail if one is found
|
||||
var previousOverwrite = channel.GetPermissionOverwrite(role);
|
||||
if (previousOverwrite.HasValue && previousOverwrite.Value.SendMessages == PermValue.Deny)
|
||||
throw new InvalidOperationException($"Role {role.Name} had already been muted in this channel.");
|
||||
|
||||
// Creates a new OverwritePermissions with send message set to deny and pass it into the method
|
||||
await channel.AddPermissionOverwriteAsync(role, new OverwritePermissions(sendMessages: PermValue.Deny));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region AddPermissionOverwriteAsyncUser
|
||||
|
||||
public async Task MuteUserAsync(IGuildUser user, IGuildChannel channel)
|
||||
{
|
||||
if (user == null) throw new ArgumentNullException(nameof(user));
|
||||
if (channel == null) throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
// Fetches the previous overwrite and bail if one is found
|
||||
var previousOverwrite = channel.GetPermissionOverwrite(user);
|
||||
if (previousOverwrite.HasValue && previousOverwrite.Value.SendMessages == PermValue.Deny)
|
||||
throw new InvalidOperationException($"User {user.Username} had already been muted in this channel.");
|
||||
|
||||
// Creates a new OverwritePermissions with send message set to deny and pass it into the method
|
||||
await channel.AddPermissionOverwriteAsync(user, new OverwritePermissions(sendMessages: PermValue.Deny));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Discord.Net.Examples.Core.Entities.Channels
|
||||
{
|
||||
[PublicAPI]
|
||||
internal class MessageChannelExamples
|
||||
{
|
||||
#region GetMessagesAsync.FromId.BeginningMessages
|
||||
|
||||
public async Task PrintFirstMessages(IMessageChannel channel, int messageCount)
|
||||
{
|
||||
// Although the library does attempt to divide the messageCount by 100
|
||||
// to comply to Discord's maximum message limit per request, sending
|
||||
// too many could still cause the queue to clog up.
|
||||
// The purpose of this exception is to discourage users from sending
|
||||
// too many requests at once.
|
||||
if (messageCount > 1000)
|
||||
throw new InvalidOperationException("Too many messages requested.");
|
||||
|
||||
// Setting fromMessageId to 0 will make Discord
|
||||
// default to the first message in channel.
|
||||
var messages = await channel.GetMessagesAsync(
|
||||
0, Direction.After, messageCount)
|
||||
.FlattenAsync();
|
||||
|
||||
// Print message content
|
||||
foreach (var message in messages)
|
||||
Console.WriteLine($"{message.Author} posted '{message.Content}' at {message.CreatedAt}.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public async Task GetMessagesExampleBody(IMessageChannel channel)
|
||||
{
|
||||
#pragma warning disable IDISP001
|
||||
#pragma warning disable IDISP014
|
||||
// We're just declaring this for the sample below.
|
||||
// Ideally, you want to get or create your HttpClient
|
||||
// from IHttpClientFactory.
|
||||
// You get a bonus for reading the example source though!
|
||||
var httpClient = new HttpClient();
|
||||
#pragma warning restore IDISP014
|
||||
#pragma warning restore IDISP001
|
||||
|
||||
// Another dummy method
|
||||
Task LongRunningAsync()
|
||||
{
|
||||
return Task.Delay(0);
|
||||
}
|
||||
|
||||
#region GetMessagesAsync.FromLimit.Standard
|
||||
|
||||
var messages = await channel.GetMessagesAsync(300).FlattenAsync();
|
||||
var userMessages = messages.Where(x => x.Author.Id == 53905483156684800);
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetMessagesAsync.FromMessage
|
||||
|
||||
var oldMessage = await channel.SendMessageAsync("boi");
|
||||
var messagesFromMsg = await channel.GetMessagesAsync(oldMessage, Direction.Before, 5).FlattenAsync();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region GetMessagesAsync.FromId.FromMessage
|
||||
|
||||
await channel.GetMessagesAsync(442012544660537354, Direction.Before, 5).FlattenAsync();
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendMessageAsync
|
||||
|
||||
var message = await channel.SendMessageAsync(DateTimeOffset.UtcNow.ToString("R"));
|
||||
await Task.Delay(TimeSpan.FromSeconds(5))
|
||||
.ContinueWith(x => message.DeleteAsync());
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendFileAsync.FilePath
|
||||
|
||||
await channel.SendFileAsync("wumpus.txt", "good discord boi");
|
||||
|
||||
#endregion
|
||||
|
||||
#region SendFileAsync.FilePath.EmbeddedImage
|
||||
|
||||
await channel.SendFileAsync("b1nzy.jpg",
|
||||
embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region SendFileAsync.FileStream.EmbeddedImage
|
||||
|
||||
using (var b1nzyStream = await httpClient.GetStreamAsync("https://example.com/b1nzy"))
|
||||
await channel.SendFileAsync(b1nzyStream, "b1nzy.jpg",
|
||||
embed: new EmbedBuilder {ImageUrl = "attachment://b1nzy.jpg"}.Build());
|
||||
|
||||
#endregion
|
||||
|
||||
#region EnterTypingState
|
||||
|
||||
using (channel.EnterTypingState()) await LongRunningAsync();
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Discord.Net.Examples.Core.Entities.Guilds
|
||||
{
|
||||
[PublicAPI]
|
||||
internal class GuildExamples
|
||||
{
|
||||
#region CreateTextChannelAsync
|
||||
public async Task CreateTextChannelUnderWumpus(IGuild guild, string name)
|
||||
{
|
||||
var categories = await guild.GetCategoriesAsync();
|
||||
var targetCategory = categories.FirstOrDefault(x => x.Name == "wumpus");
|
||||
if (targetCategory == null) return;
|
||||
await guild.CreateTextChannelAsync(name, x =>
|
||||
{
|
||||
x.CategoryId = targetCategory.Id;
|
||||
x.Topic = $"This channel was created at {DateTimeOffset.UtcNow}.";
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Discord.Net.Examples.Core.Entities.Users
|
||||
{
|
||||
[PublicAPI]
|
||||
internal class UserExamples
|
||||
{
|
||||
#region GetAvatarUrl
|
||||
|
||||
public async Task GetAvatarAsync(IUser user, ITextChannel textChannel)
|
||||
{
|
||||
var userAvatarUrl = user.GetAvatarUrl() ?? user.GetDefaultAvatarUrl();
|
||||
await textChannel.SendMessageAsync(userAvatarUrl);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetOrCreateDMChannelAsync
|
||||
|
||||
public async Task MessageUserAsync(IUser user)
|
||||
{
|
||||
var channel = await user.GetOrCreateDMChannelAsync();
|
||||
try
|
||||
{
|
||||
await channel.SendMessageAsync("Awesome stuff!");
|
||||
}
|
||||
catch (Discord.Net.HttpException ex) when (ex.HttpCode == HttpStatusCode.Forbidden)
|
||||
{
|
||||
Console.WriteLine($"Boo, I cannot message {user}.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
21
src/Discord.Net.Examples/Discord.Net.Examples.csproj
Normal file
21
src/Discord.Net.Examples/Discord.Net.Examples.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Core\Entities\Guilds\IGuild.Examples.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Core\Entities\Guilds\IGuild.Examples.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Discord.Net.Core\Discord.Net.Core.csproj" />
|
||||
<ProjectReference Include="..\Discord.Net.WebSocket\Discord.Net.WebSocket.csproj" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2018.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Discord.Net.Examples.WebSocket
|
||||
{
|
||||
[PublicAPI]
|
||||
internal class BaseSocketClientExamples
|
||||
{
|
||||
#region ReactionAdded
|
||||
|
||||
public void HookReactionAdded(BaseSocketClient client)
|
||||
=> client.ReactionAdded += HandleReactionAddedAsync;
|
||||
|
||||
public async Task HandleReactionAddedAsync(Cacheable<IUserMessage, ulong> cachedMessage,
|
||||
ISocketMessageChannel originChannel, SocketReaction reaction)
|
||||
{
|
||||
var message = await cachedMessage.GetOrDownloadAsync();
|
||||
if (message != null && reaction.User.IsSpecified)
|
||||
Console.WriteLine($"{reaction.User.Value} just added a reaction '{reaction.Emote}' " +
|
||||
$"to {message.Author}'s message ({message.Id}).");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ChannelCreated
|
||||
|
||||
public void HookChannelCreated(BaseSocketClient client)
|
||||
=> client.ChannelCreated += HandleChannelCreated;
|
||||
|
||||
public Task HandleChannelCreated(SocketChannel channel)
|
||||
{
|
||||
if (channel is SocketGuildChannel guildChannel)
|
||||
Console.WriteLine($"A new channel '{guildChannel.Name}'({guildChannel.Id}, {guildChannel.GetType()})"
|
||||
+ $"has been created at {guildChannel.CreatedAt}.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ChannelDestroyed
|
||||
|
||||
public void HookChannelDestroyed(BaseSocketClient client)
|
||||
=> client.ChannelDestroyed += HandleChannelDestroyed;
|
||||
|
||||
public Task HandleChannelDestroyed(SocketChannel channel)
|
||||
{
|
||||
if (channel is SocketGuildChannel guildChannel)
|
||||
Console.WriteLine(
|
||||
$"A new channel '{guildChannel.Name}'({guildChannel.Id}, {guildChannel.GetType()}) has been deleted.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ChannelUpdated
|
||||
|
||||
public void HookChannelUpdated(BaseSocketClient client)
|
||||
=> client.ChannelUpdated += HandleChannelRename;
|
||||
|
||||
public Task HandleChannelRename(SocketChannel beforeChannel, SocketChannel afterChannel)
|
||||
{
|
||||
if (beforeChannel is SocketGuildChannel beforeGuildChannel &&
|
||||
afterChannel is SocketGuildChannel afterGuildChannel)
|
||||
if (beforeGuildChannel.Name != afterGuildChannel.Name)
|
||||
Console.WriteLine(
|
||||
$"A channel ({beforeChannel.Id}) is renamed from {beforeGuildChannel.Name} to {afterGuildChannel.Name}.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MessageReceived
|
||||
|
||||
private readonly ulong[] _targetUserIds = {168693960628371456, 53905483156684800};
|
||||
|
||||
public void HookMessageReceived(BaseSocketClient client)
|
||||
=> client.MessageReceived += HandleMessageReceived;
|
||||
|
||||
public Task HandleMessageReceived(SocketMessage message)
|
||||
{
|
||||
// check if the message is a user message as opposed to a system message (e.g. Clyde, pins, etc.)
|
||||
if (!(message is SocketUserMessage userMessage)) return Task.CompletedTask;
|
||||
// check if the message origin is a guild message channel
|
||||
if (!(userMessage.Channel is SocketTextChannel textChannel)) return Task.CompletedTask;
|
||||
// check if the target user was mentioned
|
||||
var targetUsers = userMessage.MentionedUsers.Where(x => _targetUserIds.Contains(x.Id));
|
||||
foreach (var targetUser in targetUsers)
|
||||
Console.WriteLine(
|
||||
$"{targetUser} was mentioned in the message '{message.Content}' by {message.Author} in {textChannel.Name}.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MessageDeleted
|
||||
|
||||
public void HookMessageDeleted(BaseSocketClient client)
|
||||
=> client.MessageDeleted += HandleMessageDelete;
|
||||
|
||||
public Task HandleMessageDelete(Cacheable<IMessage, ulong> cachedMessage, ISocketMessageChannel channel)
|
||||
{
|
||||
// check if the message exists in cache; if not, we cannot report what was removed
|
||||
if (!cachedMessage.HasValue) return Task.CompletedTask;
|
||||
var message = cachedMessage.Value;
|
||||
Console.WriteLine(
|
||||
$"A message ({message.Id}) from {message.Author} was removed from the channel {channel.Name} ({channel.Id}):"
|
||||
+ Environment.NewLine
|
||||
+ message.Content);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -405,7 +405,7 @@ namespace Discord.Rest
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example creates a new text channel under an existing category named <c>Wumpus</c> with a set topic.
|
||||
/// <code lang="cs">
|
||||
/// <code language="cs">
|
||||
/// var categories = await guild.GetCategoriesAsync();
|
||||
/// var targetCategory = categories.FirstOrDefault(x => x.Name == "wumpus");
|
||||
/// if (targetCategory == null) return;
|
||||
|
||||
@@ -18,6 +18,10 @@ namespace Discord.WebSocket
|
||||
/// see the derived classes of <see cref="SocketChannel"/> for more details.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="cs" region="ChannelCreated"
|
||||
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/>
|
||||
/// </example>
|
||||
public event Func<SocketChannel, Task> ChannelCreated
|
||||
{
|
||||
add { _channelCreatedEvent.Add(value); }
|
||||
@@ -36,6 +40,10 @@ namespace Discord.WebSocket
|
||||
/// see the derived classes of <see cref="SocketChannel"/> for more details.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="cs" region="ChannelDestroyed"
|
||||
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/>
|
||||
/// </example>
|
||||
public event Func<SocketChannel, Task> ChannelDestroyed {
|
||||
add { _channelDestroyedEvent.Add(value); }
|
||||
remove { _channelDestroyedEvent.Remove(value); }
|
||||
@@ -54,6 +62,10 @@ namespace Discord.WebSocket
|
||||
/// <see cref="SocketChannel"/> for more details.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="cs" region="ChannelUpdated"
|
||||
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/>
|
||||
/// </example>
|
||||
public event Func<SocketChannel, SocketChannel, Task> ChannelUpdated {
|
||||
add { _channelUpdatedEvent.Add(value); }
|
||||
remove { _channelUpdatedEvent.Remove(value); }
|
||||
@@ -74,6 +86,11 @@ namespace Discord.WebSocket
|
||||
/// derived classes of <see cref="SocketMessage"/> for more details.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <para>The example below checks if the newly received message contains the target user.</para>
|
||||
/// <code language="cs" region="MessageReceived"
|
||||
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/>
|
||||
/// </example>
|
||||
public event Func<SocketMessage, Task> MessageReceived {
|
||||
add { _messageReceivedEvent.Add(value); }
|
||||
remove { _messageReceivedEvent.Remove(value); }
|
||||
@@ -102,6 +119,10 @@ namespace Discord.WebSocket
|
||||
/// <see cref="ISocketMessageChannel"/> parameter.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="cs" region="MessageDeleted"
|
||||
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs" />
|
||||
/// </example>
|
||||
public event Func<Cacheable<IMessage, ulong>, ISocketMessageChannel, Task> MessageDeleted {
|
||||
add { _messageDeletedEvent.Add(value); }
|
||||
remove { _messageDeletedEvent.Remove(value); }
|
||||
@@ -134,6 +155,35 @@ namespace Discord.WebSocket
|
||||
}
|
||||
internal readonly AsyncEvent<Func<Cacheable<IMessage, ulong>, SocketMessage, ISocketMessageChannel, Task>> _messageUpdatedEvent = new AsyncEvent<Func<Cacheable<IMessage, ulong>, SocketMessage, ISocketMessageChannel, Task>>();
|
||||
/// <summary> Fired when a reaction is added to a message. </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This event is fired when a reaction is added to a user message. The event handler must return a
|
||||
/// <see cref="Task"/> and accept a <see cref="Cacheable{TEntity,TId}"/>, an
|
||||
/// <see cref="ISocketMessageChannel"/>, and a <see cref="SocketReaction"/> as its parameter.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If caching is enabled via <see cref="DiscordSocketConfig"/>, the
|
||||
/// <see cref="Cacheable{TEntity,TId}"/> entity will contain the original message; otherwise, in event
|
||||
/// that the message cannot be retrieved, the snowflake ID of the message is preserved in the
|
||||
/// <see cref="ulong"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The source channel of the reaction addition will be passed into the
|
||||
/// <see cref="ISocketMessageChannel"/> parameter.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The reaction that was added will be passed into the <see cref="SocketReaction"/> parameter.
|
||||
/// </para>
|
||||
/// <note>
|
||||
/// When fetching the reaction from this event, a user may not be provided under
|
||||
/// <see cref="SocketReaction.User"/>. Please see the documentation of the property for more
|
||||
/// information.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// <code language="cs" region="ReactionAdded"
|
||||
/// source="..\Discord.Net.Examples\WebSocket\BaseSocketClient.Events.Examples.cs"/>
|
||||
/// </example>
|
||||
public event Func<Cacheable<IUserMessage, ulong>, ISocketMessageChannel, SocketReaction, Task> ReactionAdded {
|
||||
add { _reactionAddedEvent.Add(value); }
|
||||
remove { _reactionAddedEvent.Remove(value); }
|
||||
|
||||
@@ -97,13 +97,15 @@ namespace Discord.WebSocket
|
||||
/// <remarks>
|
||||
/// This method gets the user present in the WebSocket cache with the given condition.
|
||||
/// <note type="warning">
|
||||
/// Sometimes a user may return <c>null</c> due to Discord not sending offline users in large
|
||||
/// guilds (i.e. guild with 100+ members) actively. To download users on startup, consider enabling
|
||||
/// <see cref="DiscordSocketConfig.AlwaysDownloadUsers"/>.
|
||||
/// Sometimes a user may return <c>null</c> due to Discord not sending offline users in large guilds
|
||||
/// (i.e. guild with 100+ members) actively. To download users on startup and to see more information
|
||||
/// about this subject, see <see cref="Discord.WebSocket.DiscordSocketConfig.AlwaysDownloadUsers" />.
|
||||
/// </note>
|
||||
/// <note>
|
||||
/// This method does not attempt to fetch users that the logged-in user does not have access to (i.e.
|
||||
/// users who don't share mutual guild(s) with the current user).
|
||||
/// users who don't share mutual guild(s) with the current user). If you wish to get a user that you do
|
||||
/// not have access to, consider using the REST implementation of
|
||||
/// <see cref="DiscordRestClient.GetUserAsync(System.UInt64,Discord.RequestOptions)" />.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
@@ -114,20 +116,22 @@ namespace Discord.WebSocket
|
||||
/// <summary>
|
||||
/// Gets a user.
|
||||
/// </summary>
|
||||
/// <param name="username">The name of the user.</param>
|
||||
/// <param name="discriminator">The discriminator value of the user.</param>
|
||||
/// <remarks>
|
||||
/// This method gets the user present in the WebSocket cache with the given condition.
|
||||
/// <note type="warning">
|
||||
/// Sometimes a user may return <c>null</c> due to Discord not sending offline users in large
|
||||
/// guilds (i.e. guild with 100+ members) actively. To download users on startup, consider enabling
|
||||
/// <see cref="DiscordSocketConfig.AlwaysDownloadUsers"/>.
|
||||
/// Sometimes a user may return <c>null</c> due to Discord not sending offline users in large guilds
|
||||
/// (i.e. guild with 100+ members) actively. To download users on startup and to see more information
|
||||
/// about this subject, see <see cref="Discord.WebSocket.DiscordSocketConfig.AlwaysDownloadUsers" />.
|
||||
/// </note>
|
||||
/// <note>
|
||||
/// This method does not attempt to fetch users that the logged-in user does not have access to (i.e.
|
||||
/// users who don't share mutual guild(s) with the current user).
|
||||
/// users who don't share mutual guild(s) with the current user). If you wish to get a user that you do
|
||||
/// not have access to, consider using the REST implementation of
|
||||
/// <see cref="DiscordRestClient.GetUserAsync(System.UInt64,Discord.RequestOptions)" />.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
/// <param name="username">The name of the user.</param>
|
||||
/// <param name="discriminator">The discriminator value of the user.</param>
|
||||
/// <returns>
|
||||
/// A generic WebSocket-based user; <c>null</c> when the user cannot be found.
|
||||
/// </returns>
|
||||
|
||||
@@ -94,7 +94,9 @@ namespace Discord.WebSocket
|
||||
/// Please note that it can be difficult to fill the cache completely on large guilds depending on the
|
||||
/// traffic. If you are using the command system, the default user TypeReader may fail to find the user
|
||||
/// due to this issue. This may be resolved at v3 of the library. Until then, you may want to consider
|
||||
/// overriding the TypeReader and use <see cref="DiscordRestClient.GetGuildUserAsync"/> as a backup.
|
||||
/// overriding the TypeReader and use
|
||||
/// <see cref="DiscordRestClient.GetUserAsync(System.UInt64,Discord.RequestOptions)"/>
|
||||
/// or <see cref="DiscordSocketRestClient.GetGuildUserAsync(ulong, ulong, RequestOptions)"/> as a backup.
|
||||
/// </note>
|
||||
/// </remarks>
|
||||
public bool AlwaysDownloadUsers { get; set; } = false;
|
||||
|
||||
@@ -535,7 +535,7 @@ namespace Discord.WebSocket
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// The following example creates a new text channel under an existing category named <c>Wumpus</c> with a set topic.
|
||||
/// <code lang="cs">
|
||||
/// <code language="cs">
|
||||
/// var categories = await guild.GetCategoriesAsync();
|
||||
/// var targetCategory = categories.FirstOrDefault(x => x.Name == "wumpus");
|
||||
/// if (targetCategory == null) return;
|
||||
|
||||
@@ -10,6 +10,11 @@ namespace Discord.WebSocket
|
||||
/// <summary>
|
||||
/// Gets the ID of the user who added the reaction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This property retrieves the snowflake identifier of the user responsible for this reaction. This
|
||||
/// property will always contain the user identifier in event that
|
||||
/// <see cref="Discord.WebSocket.SocketReaction.User" /> cannot be retrieved.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// A user snowflake identifier associated with the user.
|
||||
/// </returns>
|
||||
@@ -17,6 +22,18 @@ namespace Discord.WebSocket
|
||||
/// <summary>
|
||||
/// Gets the user who added the reaction if possible.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This property attempts to retrieve a WebSocket-cached user that is responsible for this reaction from
|
||||
/// the client. In other words, when the user is not in the WebSocket cache, this property may not
|
||||
/// contain a value, leaving the only identifiable information to be
|
||||
/// <see cref="Discord.WebSocket.SocketReaction.UserId" />.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If you wish to obtain an identifiable user object, consider utilizing
|
||||
/// <see cref="Discord.Rest.DiscordRestClient" /> which will attempt to retrieve the user from REST.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// A user object where possible; a value is not always returned.
|
||||
/// </returns>
|
||||
|
||||
Reference in New Issue
Block a user