diff --git a/src/Discord.Net.Core/Discord.Net.Core.xml b/src/Discord.Net.Core/Discord.Net.Core.xml
index bce491f0f..076aa6db5 100644
--- a/src/Discord.Net.Core/Discord.Net.Core.xml
+++ b/src/Discord.Net.Core/Discord.Net.Core.xml
@@ -1987,6 +1987,11 @@
Represents a thread channel inside of a guild.
+
+
+ if the current user has joined this thread, otherwise .
+
+
if the current thread is archived, otherwise .
@@ -2017,6 +2022,18 @@
An approximate count of messages in a thread, stops counting at 50.
+
+
+ Joins the current thread.
+
+
+
+
+
+ Leaves the current thread.
+
+
+
Represents a generic voice channel in a guild.
@@ -4107,6 +4124,11 @@
A or .
+
+
+ A .
+
+
Provides properties that are used to modify a with the specified changes.
@@ -4502,7 +4524,8 @@
- Adds a button to the specified row.
+ Adds a with specified parameters to the at the specific row.
+ If the row cannot accept the component then it will add it to a row that can.
The label text for the newly added button.
The style of this newly added button.
@@ -4627,44 +4650,49 @@
Creates a new instance of a from instance of a .
-
+
Creates a button with the style.
- The label to use on the newly created link button.
+ The label for this link button.
The url for this link button to go to.
+ The emote for this link button
A builder with the newly created button.
-
+
Creates a button with the style.
The label for this danger button.
The custom id for this danger button.
+ The emote for this danger button
A builder with the newly created button.
-
+
Creates a button with the style.
The label for this primary button.
The custom id for this primary button.
+ The emote for this primary button
A builder with the newly created button.
-
+
Creates a button with the style.
The label for this secondary button.
The custom id for this secondary button.
+ The emote for this secondary button
A builder with the newly created button.
-
+
Creates a button with the style.
The label for this success button.
The custom id for this success button.
+ The emote for this success button
A builder with the newly created button.
diff --git a/src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs b/src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs
index 1459c954c..f801d3fd8 100644
--- a/src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs
+++ b/src/Discord.Net.Core/Entities/Channels/IThreadChannel.cs
@@ -11,6 +11,11 @@ namespace Discord
///
public interface IThreadChannel : ITextChannel, IGuildChannel
{
+ ///
+ /// if the current user has joined this thread, otherwise .
+ ///
+ bool Joined { get; }
+
///
/// if the current thread is archived, otherwise .
///
@@ -40,5 +45,17 @@ namespace Discord
/// An approximate count of messages in a thread, stops counting at 50.
///
int MessageCount { get; }
+
+ ///
+ /// Joins the current thread.
+ ///
+ ///
+ Task JoinAsync();
+
+ ///
+ /// Leaves the current thread.
+ ///
+ ///
+ Task LeaveAsync();
}
}
diff --git a/src/Discord.Net.WebSocket/API/Gateway/ThreadMembersUpdate.cs b/src/Discord.Net.WebSocket/API/Gateway/ThreadMembersUpdate.cs
new file mode 100644
index 000000000..b6acba6ae
--- /dev/null
+++ b/src/Discord.Net.WebSocket/API/Gateway/ThreadMembersUpdate.cs
@@ -0,0 +1,27 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Discord.API.Gateway
+{
+ internal class ThreadMembersUpdated
+ {
+ [JsonProperty("id")]
+ public ulong Id { get; set; }
+
+ [JsonProperty("guild_id")]
+ public ulong GuildId { get; set; }
+
+ [JsonProperty("member_count")]
+ public int MemberCount { get; set; }
+
+ [JsonProperty("added_members")]
+ public Optional AddedMembers { get; set; }
+
+ [JsonProperty("removed_member_ids")]
+ public Optional RemovedMemberIds { get; set; }
+ }
+}
diff --git a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml
index 00f22c0e8..8db8a1340 100644
--- a/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml
+++ b/src/Discord.Net.WebSocket/Discord.Net.WebSocket.xml
@@ -756,6 +756,21 @@
+
+
+ Fired when a thread is created within a guild.
+
+
+
+
+ Fired when a thread is updated within a guild.
+
+
+
+
+ Fired when a thread is deleted.
+
+
@@ -2154,6 +2169,11 @@
+
+
+ Gets a collection of threads within this text channel.
+
+
@@ -2360,9 +2380,19 @@
Represents a thread channel inside of a guild.
-
+
+
+
+ if this thread is private, otherwise
+
+
+
+
+ Gets the parent channel this thread resides in.
+
+
@@ -2848,6 +2878,14 @@
A read-only collection of category channels found within this guild.
+
+
+ Gets a collection of all thread channels in this guild.
+
+
+ A read-only collection of thread channels found within this guild.
+
+
Gets the current logged-in user.
@@ -3431,10 +3469,11 @@
- Updates the original message of the component on which the interaction was received on.
+ Updates the message which this component resides in with the type
A delegate containing the properties to modify the message with.
The request options for this async request.
+ A task that represents the asynchronous operation of updating the message.
@@ -3689,6 +3728,14 @@
The request options for this async request.
A that represents the initial response.
+
+
+ Acknowledges this interaction.
+
+
+ A task that represents the asynchronous operation of acknowledging the interaction.
+
+
Acknowledges this interaction.
@@ -4488,6 +4535,156 @@
+
+
+ Gets the this user is in.
+
+
+
+
+ Gets the timestamp for when this user joined this thread.
+
+
+
+
+ Gets the guild this user is in.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gets the guild user of this thread user.
+
+
+
Represents a WebSocket-based user that is yet to be recognized by the client.
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
index c05ff3878..c52675d66 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
@@ -1975,48 +1975,62 @@ namespace Discord.WebSocket
// Threads
case "THREAD_CREATE":
{
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false);
+ try
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
+ var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId.Value);
+ var guild = State.GetGuild(data.GuildId.Value);
- if(guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId.Value);
- return;
- }
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value);
+ return;
+ }
+
+ var threadChannel = (SocketThreadChannel)guild.AddChannel(this.State, data);
- var threadChannel = (SocketThreadChannel)guild.AddChannel(this.State, data);
+ await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false);
+ }
+ catch(Exception x)
+ {
- await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false);
+ }
}
break;
case "THREAD_UPDATE":
{
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_UPDATE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId.Value);
- if (guild == null)
+ try
{
- await UnknownGuildAsync(type, data.GuildId.Value);
- return;
- }
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_UPDATE)").ConfigureAwait(false);
- var channel = (SocketThreadChannel)guild.GetChannel(data.Id);
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value);
+ return;
+ }
- var before = channel.Clone();
- channel.Update(State, data);
+ var channel = (SocketThreadChannel)guild.GetChannel(data.Id);
- if (!(guild?.IsSynced ?? true))
- {
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
+ var before = channel.Clone();
+ channel.Update(State, data);
+
+ if (!(guild?.IsSynced ?? true))
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ await TimedInvokeAsync(_threadUpdated, nameof(ThreadUpdated), before, channel).ConfigureAwait(false);
}
+ catch(Exception x)
+ {
- await TimedInvokeAsync(_threadUpdated, nameof(ThreadUpdated), before, channel).ConfigureAwait(false);
+ }
}
break;
@@ -2071,8 +2085,20 @@ namespace Discord.WebSocket
}
break;
case "THREAD_MEMBER_UPDATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBER_UPDATE)").ConfigureAwait(false);
+ var p = payload;
+ }
+
break;
case "THREAD_MEMBERS_UPDATE": // based on intents
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBERS_UPDATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+
+ }
+
break;
//Ignored (User only)
diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs
index 9f63ad7b4..7187c9771 100644
--- a/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs
+++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketGuildChannel.cs
@@ -66,9 +66,9 @@ namespace Discord.WebSocket
internal override void Update(ClientState state, Model model)
{
Name = model.Name.Value;
- Position = model.Position.Value;
+ Position = model.Position.GetValueOrDefault(0);
- var overwrites = model.PermissionOverwrites.Value;
+ var overwrites = model.PermissionOverwrites.GetValueOrDefault(new API.Overwrite[0]);
var newOverwrites = ImmutableArray.CreateBuilder(overwrites.Length);
for (int i = 0; i < overwrites.Length; i++)
newOverwrites.Add(overwrites[i].ToEntity());
diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs
index d9583d1ea..4072276cb 100644
--- a/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs
+++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketThreadChannel.cs
@@ -2,19 +2,26 @@ using Discord.Rest;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Model = Discord.API.Channel;
+using ThreadMember = Discord.API.ThreadMember;
namespace Discord.WebSocket
{
///
/// Represents a thread channel inside of a guild.
///
+ [DebuggerDisplay(@"{DebuggerDisplay,nq}")]
public class SocketThreadChannel : SocketGuildChannel, IThreadChannel, ISocketMessageChannel
{
+
+ ///
+ public bool Joined { get; private set; }
+
///
/// if this thread is private, otherwise
///
@@ -65,6 +72,8 @@ namespace Discord.WebSocket
private readonly MessageCache _messages;
+ private string DebuggerDisplay => $"{Name} ({Id}, Thread)";
+
internal SocketThreadChannel(DiscordSocketClient discord, SocketGuild guild, ulong id, SocketTextChannel parent)
: base(discord, id, guild)
{
@@ -97,6 +106,11 @@ namespace Discord.WebSocket
}
}
+ internal void Update(ClientState state, ThreadMember self)
+ {
+
+ }
+
///
public virtual Task SyncPermissionsAsync(RequestOptions options = null)
=> ChannelHelper.SyncPermissionsAsync(this, Discord, options);
@@ -253,10 +267,10 @@ namespace Discord.WebSocket
public Task GetUsersAsync()
{
-
+ return Task.CompletedTask;
}
- private string DebuggerDisplay => $"{Name} ({Id}, Thread)";
+
internal new SocketThreadChannel Clone() => MemberwiseClone() as SocketThreadChannel;
//ITextChannel
@@ -325,22 +339,22 @@ namespace Discord.WebSocket
public Task JoinAsync()
{
-
+ return Task.CompletedTask;
}
public Task LeaveAsync()
{
-
+ return Task.CompletedTask;
}
public Task AddThreadMember(IGuildUser user)
{
-
+ return Task.CompletedTask;
}
public Task RemoveThreadMember(IGuildUser user)
{
-
+ return Task.CompletedTask;
}