Adding Entity guides, flowcharts, better sample system. (#2054)

* initial

* Interaction glossary entry

* Sharded Interaction sample

* Renames into solution

* Debugging samples

* Modify target location for webhookclient

* Finalizing docs work, resolving docfx errors.

* Adding threaduser to user chart

* Add branch info to readme.

* Edits to user chart

* Resolve format for glossary entries

* Patch sln target

* Issue with file naming fixed

* Patch 1/x for builds

* Appending suggestions
This commit is contained in:
Armano den Boef
2022-01-27 14:50:49 +01:00
committed by GitHub
parent b0f59e3eb9
commit b14af1c008
57 changed files with 1059 additions and 344 deletions

View File

@@ -53,7 +53,7 @@ able to message.
You may check the message channel type. Visit [Glossary] to see the
various types of channels.
[glossary]: xref:FAQ.Glossary#message-channels
[Glossary]: xref:Guides.Entities.Glossary#channels
## How can I get the guild from a message?

View File

@@ -24,6 +24,6 @@ Visit the repo's [release tag] to see the latest public pre-release.
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).
[here](https://github.com/Discord-Net-Labs/Discord.Net-Labs/blob/release/3.x/samples/InteractionFramework/Program.cs#L66).
[DependencyInjection]: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection

View File

@@ -16,7 +16,5 @@
topicUid: FAQ.Commands.Interactions
- name: Dependency Injection
topicUid: FAQ.Commands.DI
- name: Glossary
topicUid: FAQ.Glossary
- name: Legacy or Upgrade
topicUid: FAQ.Legacy

View File

@@ -0,0 +1,68 @@
---
uid: Guides.Entities.Casting
title: Casting & Unboxing
---
# Casting
Casting can be done in many ways, and is the only method to box and unbox types to/from their base definition.
Casting only works for types that inherit the base type that you want to unbox from.
`IUser` cannot be cast to `IMessage`.
> [!NOTE]
> Interfaces **can** be cast to other interfaces, as long as they inherit each other.
> The same goes for reverse casting. As long as some entity can be simplified into what it inherits, your cast will pass.
## Boxing
A boxed object is the definition of an object that was simplified (or trimmed) by incoming traffic,
but still owns the data of the originally constructed type. Boxing is an implicit operation.
Through casting, we can **unbox** this type, and access the properties that were unaccessible before.
## Unboxing
Unboxing is the most direct way to access the real definition of an object.
If we want to return a type from its interface, we can unbox it directly.
[!code-csharp[Unboxing](samples/unboxing.cs)]
## Regular casting
In 'regular' casting, we use the `as` keyword to assign the given type to the object.
If the boxed type can indeed be cast into given type,
it will become said type, and its properties can be accessed.
[!code-csharp[Casting](samples/casting.cs)]
> [!WARNING]
> If the type you're casting to is null, a `NullReferenceException` will be thrown when it's called.
> This makes safety casting much more interesting to use, as it prevents this exception from being thrown.
## Safety casting
Safety casting makes sure that the type you're trying to cast to can never be null, as it passes checks upon calling them.
There are 3 different ways to safety cast an object:
### Basic safety casting:
To safety cast an object, all we need to do is check if it is of the member type in a statement.
If this check fails, it will continue below, making sure we don't try to access null.
[!code-csharp[Base](samples/safety-cast.cs)]
### Object declaration:
Here we declare the object we are casting to,
making it so that you can immediately work with its properties without reassigning through regular casting.
[!code-csharp[Declare](samples/safety-cast-var.cs)]
### Reverse passage:
In previous examples, we want to let code continue running after the check, or if the check fails.
In this example, the cast will return the entire method (ignoring the latter) upon failure,
and declare the variable for further use into the method:
[!code-csharp[Pass](samples/safety-cast-pass.cs)]
> [!NOTE]
> Usage of `is`, `not` and `as` is required in cast assignment and/or type checks. `==`, `!=` and `=` are invalid assignment,
> as these operators only apply to initialized objects and not their types.

View File

@@ -1,29 +1,19 @@
---
uid: FAQ.Glossary
title: Common Terminologies / Glossary
uid: Guides.Entities.Glossary
title: Glossary & Flowcharts
---
# Glossary
# Entity Types
This is an additional chapter for quick references to various common
types that you may see within Discord.Net. To see more information
regarding each type of object, click on the object to navigate
to our API documentation page where you might find more explanation
about it.
A list of all Discord.Net entities, what they can be cast to and what their properties are.
## Common Types
> [!NOTE]
> All interfaces have the same inheritance tree for both `Socket` and `Rest` entities.
> Entities with that have been marked red are exclusive to the project they source from.
* 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 a generic channel.
- Example: #dotnet_discord-net
- See [Channel Types](#channel-types)
## Channels
[IGuild]: xref:Discord.IGuild
[IChannel]: xref:Discord.IChannel
## Channel Types
![IChannelChart](images/IChannel.png)
### Message Channels
* A **Text Channel** ([ITextChannel]) is a message channel from a Guild.
@@ -40,14 +30,11 @@ channels, and are often referred to as "servers".
- This can be any channels that may exist in a guild.
* A **Voice Channel** ([IVoiceChannel]) is a voice channel in a guild.
* A **Stage Channel** ([IStageChannel]) is a stage channel in a guild.
* A **Category Channel** ([ICategoryChannel]) (2.0+) is a category that
* A **Category Channel** ([ICategoryChannel]) is a category that
holds one or more sub-channels.
* A **Nested Channel** ([INestedChannel]) (2.0+) is a channel that can
* A **Nested Channel** ([INestedChannel]) is a channel that can
exist under a category.
> [!NOTE]
> A Channel ([IChannel]) can be all types of channels.
[INestedChannel]: xref:Discord.INestedChannel
[IGuildChannel]: xref:Discord.IGuildChannel
[IMessageChannel]: xref:Discord.IMessageChannel
@@ -62,17 +49,27 @@ exist under a category.
[IStageChannel]: xref:Discord.IStageChannel
[INewsChannel]: xref:Discord.INewsChannel
## Message Types
## Messages
![IMessageChart](images/IMessage.png)
* A **Rest Followup Message** ([RestFollowupMessage]) is a message returned by followup on on an interaction.
* A **Rest Interaction Message** ([RestInteractionMessage]) is a message returned by the interaction's original response.
* A **Rest User Message** ([RestUserMessage]) is a message sent over rest; it can be any of the above.
* An **User Message** ([IUserMessage]) is a message sent by a user.
* A **System Message** ([ISystemMessage]) is a message sent by Discord itself.
* A **Message** ([IMessage]) can be any of the above.
[RestFollowupMessage]: xref:Discord.Rest.RestFollowupMessage
[RestInteractionMessage]: xref:Discord.Rest.RestInteractionMessage
[RestUserMEssage]: xref:Discord.Rest.RestUserMessage
[IUserMessage]: xref:Discord.IUserMessage
[ISystemMessage]: xref:Discord.ISystemMessage
[IMessage]: xref:Discord.IMessage
## User Types
## Users
![IUserChart](images/IUser.png)
* A **Guild User** ([IGuildUser]) is a user available inside a guild.
* A **Group User** ([IGroupUser]) is a user available inside a group.
@@ -85,7 +82,29 @@ exist under a category.
[ISelfUser]: xref:Discord.ISelfUser
[IUser]: xref:Discord.IUser
## Emoji Types
## Interactions
![IInteractionChart](images/IInteraction.png)
* A **Slash command** ([ISlashCommandInteraction]) is an application command executed in the text box, with provided parameters.
* A **Message Command** ([IMessageCommandInteraction]) is an application command targetting a message.
* An **User Command** ([IUserCommandInteraction]) is an application command targetting a user.
* An **Application Command** ([IApplicationCommandInteraction]) is any of the above.
* A **Message component** ([IMessageComponent]) is the interaction of a button being clicked/dropdown option(s) entered.
* An **Autocomplete Interaction** ([IAutocompleteinteraction]) is an interaction that has been automatically completed.
* An **Interaction** ([IDiscordInteraction]) is any of the above.
[ISlashCommandInteraction]: xref:Discord.ISlashCommandInteraction
[IMessageCommandInteraction]: xref:Discord.IMessageCommandInteraction
[IUserCommandInteraction]: xref:Discord.IUserCommandInteraction
[IApplicationCommandInteraction]: xref:Discord.IApplicationCommandInteraction
[IMessageComponent]: xref:Discord.IMessageComponent
[IAutocompleteinteraction]: xref:Discord.IAutocompleteInteraction
[IDiscordInteraction]: xref:Discord.IDiscordInteraction
## Other types:
### Emoji
* An **Emote** ([Emote]) is a custom emote from a guild.
- Example: `<:dotnet:232902710280716288>`
@@ -95,8 +114,7 @@ exist under a category.
[Emote]: xref:Discord.Emote
[Emoji]: xref:Discord.Emoji
## Sticker Types
### Stickers
* A **Sticker** ([ISticker]) is a standard Discord sticker.
* A **Custom Sticker ([ICustomSticker]) is a Guild-unique sticker.
@@ -104,7 +122,7 @@ exist under a category.
[ISticker]: xref:Discord.ISticker
[ICustomSticker]: xref:Discord.ICustomSticker
## Activity Types
### Activity
* A **Game** ([Game]) refers to a user's game activity.
* A **Rich Presence** ([RichGame]) refers to a user's detailed

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

View File

@@ -1,26 +1,41 @@
---
uid: Guides.Concepts.Entities
title: Entities
uid: Guides.Entities.Intro
title: Introduction
---
# Entities in Discord.Net
> [!NOTE]
> This article is written with the Socket variants of entities in mind,
> not the general interfaces or Rest entities.
Discord.Net provides a versatile entity system for navigating the
Discord API.
> [!TIP]
> It is **vital** that you use the proper IDs for an entity when using
> a `GetXXX` method. It is recommended that you enable Discord's
> _developer mode_ to allow easy access to entity IDs, found in
> Settings > Appearance > Advanced. Read more about it in the
> [FAQ](xref:FAQ.Basics.GetStarted) page.
## Inheritance
Due to the nature of the Discord API, some entities are designed with
multiple variants; for example, `SocketUser` and `SocketGuildUser`.
multiple variants; for example, `IUser` and `IGuildUser`.
All models will contain the most detailed version of an entity
possible, even if the type is less detailed.
For example, in the case of the `MessageReceived` event, a
## Socket & REST
REST entities are retrieved over REST, and will be disposed after use.
It is suggested to limit the amount of REST calls as much as possible,
as calls over REST interact with the API, and are thus prone to rate-limits.
- [Learn more about REST](https://restfulapi.net/)
Socket entities are created through the gateway,
most commonly through `DiscordSocketClient` events.
These entities will enter the clients' global cache for later use.
In the case of the `MessageReceived` event, a
`SocketMessage` is passed in with a channel property of type
`SocketMessageChannel`. All messages come from channels capable of
messaging, so this is the only variant of a channel that can cover
@@ -31,7 +46,9 @@ But that doesn't mean a message _can't_ come from a
retrieve information about a guild from a message entity, you will
need to cast its channel object to a `SocketTextChannel`.
You can find out various types of entities in the [Glossary page.](xref:FAQ.Glossary)
> [!NOTE]
> You can find out the inheritance tree & definitions of various entities
> [here](xref:Guides.Entities.Glossary)
## Navigation
@@ -40,26 +57,31 @@ you to easily navigate to an entity's parent or children. As explained
above, you will sometimes need to cast to a more detailed version of
an entity to navigate to its parent.
## Accessing Entities
## Accessing Socket Entities
The most basic forms of entities, `SocketGuild`, `SocketUser`, and
`SocketChannel` can be pulled from the DiscordSocketClient's global
cache, and can be retrieved using the respective `GetXXX` method on
DiscordSocketClient.
> [!TIP]
> It is **vital** that you use the proper IDs for an entity when using
> a `GetXXX` method. It is recommended that you enable Discord's
> _developer mode_ to allow easy access to entity IDs, found in
> Settings > Appearance > Advanced. Read more about it in the
> [FAQ](xref:FAQ.Basics.GetStarted) page.
More detailed versions of entities can be pulled from the basic
entities, e.g., `SocketGuild.GetUser`, which returns a
`SocketGuildUser`, or `SocketGuild.GetChannel`, which returns a
`SocketGuildChannel`. Again, you may need to cast these objects to get
a variant of the type that you need.
## Sample
### Sample
[!code-csharp[Entity Sample](samples/entities.cs)]
[!code-csharp[Socket Sample](samples/socketentities.cs)]
## Accessing REST Entities
REST entities work almost the same as Socket entities, but are much less frequently used.
To access REST entities, the `DiscordSocketClient`'s `Rest` property is required.
Another option here is to create your own [DiscordRestClient], independent of the Socket gateway.
[DiscordRestClient]: xref:Discord.Rest.DiscordRestClient
### Sample
[!code-csharp[Rest Sample](samples/restentities.cs)]

View File

@@ -0,0 +1,7 @@
// Say we have an entity; for the simplicity of this example, it will appear from thin air.
IChannel channel;
// If we want this to be an ITextChannel so we can access the properties of a text channel inside of a guild, an approach would be:
ITextChannel textChannel = channel as ITextChannel;
await textChannel.DoSomethingICantWithIChannelAsync();

View File

@@ -0,0 +1,8 @@
// RestUser entities expose the accent color and banner of a user.
// This being one of the few use-cases for requesting a RestUser instead of depending on the Socket counterpart.
public static EmbedBuilder WithUserColor(this EmbedBuilder builder, IUser user)
{
var restUser = await _client.Rest.GetUserAsync(user.Id);
return builder.WithColor(restUser.AccentColor ?? Color.Blue);
// The accent color can still be null, so a check for this needs to be done to prevent an exception to be thrown.
}

View File

@@ -0,0 +1,10 @@
private void MyFunction(IMessage message)
{
// Here we do the reverse as in the previous examples, and let it continue the code below if it IS an IUserMessage
if (message is not IUserMessage userMessage)
return;
// Because we do the above check inline (don't give the statement a body),
// the code will still declare `userMessage` as available outside of the above statement.
Console.WriteLine(userMessage.Author);
}

View File

@@ -0,0 +1,9 @@
IUser user;
// Here we can pre-define the actual declaration of said IGuildUser object,
// so we don't need to cast additionally inside of the statement.
if (user is IGuildUser guildUser)
{
Console.WriteLine(guildUser.JoinedAt);
}
// Check failed.

View File

@@ -0,0 +1,8 @@
IUser user;
// Here we check if the user is an IGuildUser, if not, let it pass. This ensures its not null.
if (user is IGuildUser)
{
Console.WriteLine("This user is in a guild!");
}
// Check failed.

View File

@@ -0,0 +1,9 @@
IUser user;
// Here we use inline unboxing to make a call to its member (if available) only once.
// Note that if the entity we're trying to cast to is null, this will throw a NullReferenceException.
Console.WriteLine(((IGuildUser)user).Nickname);
// In case you are certain the entity IS said member, you can also use unboxing to declare variables.
IGuildUser guildUser = (IGuildUser)user;

View File

@@ -21,8 +21,14 @@
topicUid: Guides.Concepts.Events
- name: Managing Connections
topicUid: Guides.Concepts.ManageConnections
- name: Entities
topicUid: Guides.Concepts.Entities
- name: Entities
items:
- name: Introduction
topicUid: Guides.Entities.Intro
- name: Casting
topicUid: Guides.Entities.Casting
- name: Glossary & Flowcharts
topicUid: Guides.Entities.Glossary
- name: Working with Text-based Commands
items:
- name: Introduction