@@ -3,7 +3,7 @@ using System.Collections.Generic; | |||
namespace Discord.API | |||
{ | |||
internal class ApplicationCommandInteractionData : IDiscordInteractionData | |||
internal class ApplicationCommandInteractionData : IResolvable, IDiscordInteractionData | |||
{ | |||
[JsonProperty("id")] | |||
public ulong Id { get; set; } | |||
@@ -18,7 +18,7 @@ namespace Discord.API | |||
public Optional<ApplicationCommandInteractionDataResolved> Resolved { get; set; } | |||
[JsonProperty("type")] | |||
public Optional<ApplicationCommandType> Type { get; set; } | |||
public ApplicationCommandType Type { get; set; } | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Discord.API | |||
{ | |||
internal interface IResolvable | |||
{ | |||
Optional<ApplicationCommandInteractionDataResolved> Resolved { get; } | |||
} | |||
} |
@@ -3617,8 +3617,16 @@ | |||
Represents the data tied with the <see cref="T:Discord.WebSocket.SocketMessageCommand"/> interaction. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketMessageCommandData.Name"> | |||
<member name="P:Discord.WebSocket.SocketMessageCommandData.Message"> | |||
<summary> | |||
Gets the messagte associated with this message command. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketMessageCommandData.Options"> | |||
<inheritdoc/> | |||
<remarks> | |||
<b>Note</b> Not implemented for <see cref="T:Discord.WebSocket.SocketMessageCommandData"/> | |||
</remarks> | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketUserCommand"> | |||
<summary> | |||
@@ -3635,8 +3643,16 @@ | |||
Represents the data tied with the <see cref="T:Discord.WebSocket.SocketUserCommand"/> interaction. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketUserCommandData.Name"> | |||
<member name="P:Discord.WebSocket.SocketUserCommandData.Member"> | |||
<summary> | |||
The user used to run the command | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketUserCommandData.Options"> | |||
<inheritdoc/> | |||
<remarks> | |||
<b>Note</b> Not implemented for <see cref="T:Discord.WebSocket.SocketUserCommandData"/> | |||
</remarks> | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketMessageComponent"> | |||
<summary> | |||
@@ -3715,14 +3731,6 @@ | |||
Represents the data tied with the <see cref="T:Discord.WebSocket.SocketSlashCommand"/> interaction. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketSlashCommandData.Name"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketSlashCommandData.Options"> | |||
<summary> | |||
The <see cref="T:Discord.WebSocket.SocketSlashCommandDataOption"/>'s received with this interaction. | |||
</summary> | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketSlashCommandDataOption"> | |||
<summary> | |||
Represents a Websocket-based <see cref="T:Discord.IApplicationCommandInteractionDataOption"/> recieved by the gateway | |||
@@ -3821,7 +3829,7 @@ | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketCommandBase"> | |||
<summary> | |||
Base class for User, Message, and Slash command interactions | |||
Base class for User, Message, and Slash command interactions | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketCommandBase.Data"> | |||
@@ -3843,36 +3851,22 @@ | |||
A task that represents the asynchronous operation of acknowledging the interaction. | |||
</returns> | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketCommandBaseData"> | |||
<member name="T:Discord.WebSocket.SocketCommandBaseData`1"> | |||
<summary> | |||
Represents the base data tied with the <see cref="T:Discord.WebSocket.SocketCommandBase"/> interaction. | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseData.Name"> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseData`1.Name"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseData.Options"> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseData`1.Options"> | |||
<summary> | |||
The <see cref="T:Discord.WebSocket.SocketCommandBaseDataOption"/>'s received with this interaction. | |||
The <typeparamref name="TOption"/> received with this interaction. | |||
</summary> | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketCommandBaseDataOption"> | |||
<summary> | |||
Represents the base Websocket-based <see cref="T:Discord.IApplicationCommandInteractionDataOption"/> recieved by the gateway | |||
</summary> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseDataOption.Name"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseDataOption.Value"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseDataOption.Type"> | |||
<inheritdoc/> | |||
</member> | |||
<member name="P:Discord.WebSocket.SocketCommandBaseDataOption.Options"> | |||
<member name="T:Discord.WebSocket.SocketCommandBaseData"> | |||
<summary> | |||
The sub command options received for this sub command group. | |||
Represents the base data tied with the <see cref="T:Discord.WebSocket.SocketCommandBase"/> interaction. | |||
</summary> | |||
</member> | |||
<member name="T:Discord.WebSocket.SocketInteraction"> | |||
@@ -15,7 +15,7 @@ namespace Discord.WebSocket | |||
/// <summary> | |||
/// The data associated with this interaction. | |||
/// </summary> | |||
new public SocketMessageCommandData Data { get; } | |||
public new SocketMessageCommandData Data { get; } | |||
internal SocketMessageCommand(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | |||
: base(client, model, channel) | |||
@@ -1,5 +1,4 @@ | |||
using System.Collections.Generic; | |||
using System.Collections.Immutable; | |||
using System.Linq; | |||
using Model = Discord.API.ApplicationCommandInteractionData; | |||
@@ -8,132 +7,29 @@ namespace Discord.WebSocket | |||
/// <summary> | |||
/// Represents the data tied with the <see cref="SocketMessageCommand"/> interaction. | |||
/// </summary> | |||
public class SocketMessageCommandData : SocketEntity<ulong>, IApplicationCommandInteractionData | |||
public class SocketMessageCommandData : SocketCommandBaseData | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <summary> | |||
/// The message selected to run the command | |||
/// Gets the messagte associated with this message command. | |||
/// </summary> | |||
public SocketMessage Message { get; private set; } | |||
internal Dictionary<ulong, SocketGuildUser> guildMembers { get; private set; } | |||
= new Dictionary<ulong, SocketGuildUser>(); | |||
internal Dictionary<ulong, SocketGlobalUser> users { get; private set; } | |||
= new Dictionary<ulong, SocketGlobalUser>(); | |||
internal Dictionary<ulong, SocketChannel> channels { get; private set; } | |||
= new Dictionary<ulong, SocketChannel>(); | |||
internal Dictionary<ulong, SocketRole> roles { get; private set; } | |||
= new Dictionary<ulong, SocketRole>(); | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionData.Options => throw new System.NotImplementedException(); | |||
public SocketMessage Message | |||
=> ResolvableData?.Messages.FirstOrDefault().Value; | |||
private ulong? guildId; | |||
/// <inheritdoc/> | |||
/// <remarks> | |||
/// <b>Note</b> Not implemented for <see cref="SocketMessageCommandData"/> | |||
/// </remarks> | |||
public override IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options | |||
=> throw new System.NotImplementedException(); | |||
internal SocketMessageCommandData(DiscordSocketClient client, Model model, ulong? guildId) | |||
: base(client, model.Id) | |||
{ | |||
this.guildId = guildId; | |||
if (model.Resolved.IsSpecified) | |||
{ | |||
var guild = this.guildId.HasValue ? Discord.GetGuild(this.guildId.Value) : null; | |||
var resolved = model.Resolved.Value; | |||
if (resolved.Users.IsSpecified) | |||
{ | |||
foreach (var user in resolved.Users.Value) | |||
{ | |||
var socketUser = Discord.GetOrCreateUser(this.Discord.State, user.Value); | |||
this.users.Add(ulong.Parse(user.Key), socketUser); | |||
} | |||
} | |||
if (resolved.Channels.IsSpecified) | |||
{ | |||
foreach (var channel in resolved.Channels.Value) | |||
{ | |||
SocketChannel socketChannel = guild != null | |||
? guild.GetChannel(channel.Value.Id) | |||
: Discord.GetChannel(channel.Value.Id); | |||
if (socketChannel == null) | |||
{ | |||
var channelModel = guild != null | |||
? Discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult() | |||
: Discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult(); | |||
: base(client, model, guildId) { } | |||
socketChannel = guild != null | |||
? SocketGuildChannel.Create(guild, Discord.State, channelModel) | |||
: (SocketChannel)SocketChannel.CreatePrivate(Discord, Discord.State, channelModel); | |||
} | |||
Discord.State.AddChannel(socketChannel); | |||
this.channels.Add(ulong.Parse(channel.Key), socketChannel); | |||
} | |||
} | |||
if (resolved.Members.IsSpecified) | |||
{ | |||
foreach (var member in resolved.Members.Value) | |||
{ | |||
member.Value.User = resolved.Users.Value[member.Key]; | |||
var user = guild.AddOrUpdateUser(member.Value); | |||
this.guildMembers.Add(ulong.Parse(member.Key), user); | |||
} | |||
} | |||
if (resolved.Roles.IsSpecified) | |||
{ | |||
foreach (var role in resolved.Roles.Value) | |||
{ | |||
var socketRole = guild.AddOrUpdateRole(role.Value); | |||
this.roles.Add(ulong.Parse(role.Key), socketRole); | |||
} | |||
} | |||
if (resolved.Messages.IsSpecified) | |||
{ | |||
foreach (var msg in resolved.Messages.Value) | |||
{ | |||
var channel = client.GetChannel(msg.Value.ChannelId) as ISocketMessageChannel; | |||
SocketUser author; | |||
if (guild != null) | |||
{ | |||
if (msg.Value.WebhookId.IsSpecified) | |||
author = SocketWebhookUser.Create(guild, client.State, msg.Value.Author.Value, msg.Value.WebhookId.Value); | |||
else | |||
author = guild.GetUser(msg.Value.Author.Value.Id); | |||
} | |||
else | |||
author = (channel as SocketChannel).GetUser(msg.Value.Author.Value.Id); | |||
if (channel == null) | |||
{ | |||
if (!msg.Value.GuildId.IsSpecified) // assume it is a DM | |||
{ | |||
channel = client.CreateDMChannel(msg.Value.ChannelId, msg.Value.Author.Value, client.State); | |||
} | |||
} | |||
this.Message = SocketMessage.Create(client, client.State, author, channel, msg.Value); | |||
} | |||
} | |||
} | |||
} | |||
internal static SocketMessageCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) | |||
internal new static SocketMessageCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) | |||
{ | |||
var entity = new SocketMessageCommandData(client, model, guildId); | |||
entity.Update(model); | |||
return entity; | |||
} | |||
internal void Update(Model model) | |||
{ | |||
this.Name = model.Name; | |||
} | |||
} | |||
} |
@@ -15,7 +15,7 @@ namespace Discord.WebSocket | |||
/// <summary> | |||
/// The data associated with this interaction. | |||
/// </summary> | |||
new public SocketUserCommandData Data { get; } | |||
public new SocketUserCommandData Data { get; } | |||
internal SocketUserCommand(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | |||
: base(client, model, channel) | |||
@@ -1,6 +1,4 @@ | |||
using System.Collections.Generic; | |||
using System.Collections.Immutable; | |||
using System.Linq; | |||
using Model = Discord.API.ApplicationCommandInteractionData; | |||
namespace Discord.WebSocket | |||
@@ -8,104 +6,28 @@ namespace Discord.WebSocket | |||
/// <summary> | |||
/// Represents the data tied with the <see cref="SocketUserCommand"/> interaction. | |||
/// </summary> | |||
public class SocketUserCommandData : SocketEntity<ulong>, IApplicationCommandInteractionData | |||
public class SocketUserCommandData : SocketCommandBaseData | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <summary> | |||
/// The user used to run the command | |||
/// The user used to run the command | |||
/// </summary> | |||
public SocketUser Member { get; private set; } | |||
internal Dictionary<ulong, SocketGuildUser> guildMembers { get; private set; } | |||
= new Dictionary<ulong, SocketGuildUser>(); | |||
internal Dictionary<ulong, SocketGlobalUser> users { get; private set; } | |||
= new Dictionary<ulong, SocketGlobalUser>(); | |||
internal Dictionary<ulong, SocketChannel> channels { get; private set; } | |||
= new Dictionary<ulong, SocketChannel>(); | |||
internal Dictionary<ulong, SocketRole> roles { get; private set; } | |||
= new Dictionary<ulong, SocketRole>(); | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionData.Options => throw new System.NotImplementedException(); | |||
private ulong? guildId; | |||
/// <inheritdoc/> | |||
/// <remarks> | |||
/// <b>Note</b> Not implemented for <see cref="SocketUserCommandData"/> | |||
/// </remarks> | |||
public override IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options | |||
=> throw new System.NotImplementedException(); | |||
internal SocketUserCommandData(DiscordSocketClient client, Model model, ulong? guildId) | |||
: base(client, model.Id) | |||
{ | |||
this.guildId = guildId; | |||
if (model.Resolved.IsSpecified) | |||
{ | |||
var guild = this.guildId.HasValue ? Discord.GetGuild(this.guildId.Value) : null; | |||
var resolved = model.Resolved.Value; | |||
if (resolved.Users.IsSpecified) | |||
{ | |||
foreach (var user in resolved.Users.Value) | |||
{ | |||
var socketUser = Discord.GetOrCreateUser(this.Discord.State, user.Value); | |||
this.users.Add(ulong.Parse(user.Key), socketUser); | |||
} | |||
} | |||
: base(client, model, guildId) { } | |||
if (resolved.Channels.IsSpecified) | |||
{ | |||
foreach (var channel in resolved.Channels.Value) | |||
{ | |||
SocketChannel socketChannel = guild != null | |||
? guild.GetChannel(channel.Value.Id) | |||
: Discord.GetChannel(channel.Value.Id); | |||
if (socketChannel == null) | |||
{ | |||
var channelModel = guild != null | |||
? Discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult() | |||
: Discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult(); | |||
socketChannel = guild != null | |||
? SocketGuildChannel.Create(guild, Discord.State, channelModel) | |||
: (SocketChannel)SocketChannel.CreatePrivate(Discord, Discord.State, channelModel); | |||
} | |||
Discord.State.AddChannel(socketChannel); | |||
this.channels.Add(ulong.Parse(channel.Key), socketChannel); | |||
} | |||
} | |||
if (resolved.Members.IsSpecified) | |||
{ | |||
foreach (var member in resolved.Members.Value) | |||
{ | |||
member.Value.User = resolved.Users.Value[member.Key]; | |||
var user = guild.AddOrUpdateUser(member.Value); | |||
this.guildMembers.Add(ulong.Parse(member.Key), user); | |||
this.Member = user; | |||
} | |||
} | |||
if (resolved.Roles.IsSpecified) | |||
{ | |||
foreach (var role in resolved.Roles.Value) | |||
{ | |||
var socketRole = guild.AddOrUpdateRole(role.Value); | |||
this.roles.Add(ulong.Parse(role.Key), socketRole); | |||
} | |||
} | |||
} | |||
} | |||
internal static SocketUserCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) | |||
internal new static SocketUserCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) | |||
{ | |||
var entity = new SocketUserCommandData(client, model, guildId); | |||
entity.Update(model); | |||
return entity; | |||
} | |||
internal void Update(Model model) | |||
{ | |||
this.Name = model.Name; | |||
} | |||
} | |||
} |
@@ -28,7 +28,7 @@ namespace Discord.WebSocket | |||
if (this.Channel is SocketGuildChannel guildChannel) | |||
guildId = guildChannel.Guild.Id; | |||
Data = SocketSlashCommandData.Create(client, dataModel, model.Id, guildId); | |||
Data = SocketSlashCommandData.Create(client, dataModel, guildId); | |||
} | |||
new internal static SocketInteraction Create(DiscordSocketClient client, Model model, ISocketMessageChannel channel) | |||
@@ -8,108 +8,24 @@ namespace Discord.WebSocket | |||
/// <summary> | |||
/// Represents the data tied with the <see cref="SocketSlashCommand"/> interaction. | |||
/// </summary> | |||
public class SocketSlashCommandData : SocketEntity<ulong>, IApplicationCommandInteractionData | |||
public class SocketSlashCommandData : SocketCommandBaseData<SocketSlashCommandDataOption> | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <summary> | |||
/// The <see cref="SocketSlashCommandDataOption"/>'s received with this interaction. | |||
/// </summary> | |||
public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | |||
internal Dictionary<ulong, SocketGuildUser> guildMembers { get; private set; } | |||
= new Dictionary<ulong, SocketGuildUser>(); | |||
internal Dictionary<ulong, SocketGlobalUser> users { get; private set; } | |||
= new Dictionary<ulong, SocketGlobalUser>(); | |||
internal Dictionary<ulong, SocketChannel> channels { get; private set; } | |||
= new Dictionary<ulong, SocketChannel>(); | |||
internal Dictionary<ulong, SocketRole> roles { get; private set; } | |||
= new Dictionary<ulong, SocketRole>(); | |||
private ulong? guildId; | |||
internal SocketSlashCommandData(DiscordSocketClient client, Model model, ulong? guildId) | |||
: base(client, model.Id) | |||
{ | |||
this.guildId = guildId; | |||
if (model.Resolved.IsSpecified) | |||
{ | |||
var guild = this.guildId.HasValue ? Discord.GetGuild(this.guildId.Value) : null; | |||
var resolved = model.Resolved.Value; | |||
if (resolved.Users.IsSpecified) | |||
{ | |||
foreach (var user in resolved.Users.Value) | |||
{ | |||
var socketUser = Discord.GetOrCreateUser(this.Discord.State, user.Value); | |||
this.users.Add(ulong.Parse(user.Key), socketUser); | |||
} | |||
} | |||
: base(client, model, guildId) { } | |||
if (resolved.Channels.IsSpecified) | |||
{ | |||
foreach (var channel in resolved.Channels.Value) | |||
{ | |||
SocketChannel socketChannel = guild != null | |||
? guild.GetChannel(channel.Value.Id) | |||
: Discord.GetChannel(channel.Value.Id); | |||
if (socketChannel == null) | |||
{ | |||
var channelModel = guild != null | |||
? Discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult() | |||
: Discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult(); | |||
socketChannel = guild != null | |||
? SocketGuildChannel.Create(guild, Discord.State, channelModel) | |||
: (SocketChannel)SocketChannel.CreatePrivate(Discord, Discord.State, channelModel); | |||
} | |||
Discord.State.AddChannel(socketChannel); | |||
this.channels.Add(ulong.Parse(channel.Key), socketChannel); | |||
} | |||
} | |||
if (resolved.Members.IsSpecified) | |||
{ | |||
foreach (var member in resolved.Members.Value) | |||
{ | |||
member.Value.User = resolved.Users.Value[member.Key]; | |||
var user = guild.AddOrUpdateUser(member.Value); | |||
this.guildMembers.Add(ulong.Parse(member.Key), user); | |||
} | |||
} | |||
if (resolved.Roles.IsSpecified) | |||
{ | |||
foreach (var role in resolved.Roles.Value) | |||
{ | |||
var socketRole = guild.AddOrUpdateRole(role.Value); | |||
this.roles.Add(ulong.Parse(role.Key), socketRole); | |||
} | |||
} | |||
} | |||
} | |||
internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong id, ulong? guildId) | |||
internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong? guildId) | |||
{ | |||
var entity = new SocketSlashCommandData(client, model, guildId); | |||
entity.Update(model); | |||
return entity; | |||
} | |||
internal void Update(Model model) | |||
internal override void Update(Model model) | |||
{ | |||
this.Name = model.Name; | |||
base.Update(model); | |||
this.Options = model.Options.IsSpecified | |||
? model.Options.Value.Select(x => new SocketSlashCommandDataOption(this, x)).ToImmutableArray() | |||
: null; | |||
} | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionData.Options => Options; | |||
} | |||
} |
@@ -44,34 +44,34 @@ namespace Discord.WebSocket | |||
{ | |||
case ApplicationCommandOptionType.User: | |||
{ | |||
var guildUser = data.guildMembers.FirstOrDefault(x => x.Key == valueId).Value; | |||
var guildUser = data.ResolvableData.GuildMembers.FirstOrDefault(x => x.Key == valueId).Value; | |||
if (guildUser != null) | |||
this.Value = guildUser; | |||
else | |||
this.Value = data.users.FirstOrDefault(x => x.Key == valueId).Value; | |||
this.Value = data.ResolvableData.Users.FirstOrDefault(x => x.Key == valueId).Value; | |||
} | |||
break; | |||
case ApplicationCommandOptionType.Channel: | |||
this.Value = data.channels.FirstOrDefault(x => x.Key == valueId).Value; | |||
this.Value = data.ResolvableData.Channels.FirstOrDefault(x => x.Key == valueId).Value; | |||
break; | |||
case ApplicationCommandOptionType.Role: | |||
this.Value = data.roles.FirstOrDefault(x => x.Key == valueId).Value; | |||
this.Value = data.ResolvableData.Roles.FirstOrDefault(x => x.Key == valueId).Value; | |||
break; | |||
case ApplicationCommandOptionType.Mentionable: | |||
{ | |||
if(data.guildMembers.Any(x => x.Key == valueId) || data.users.Any(x => x.Key == valueId)) | |||
if(data.ResolvableData.GuildMembers.Any(x => x.Key == valueId) || data.ResolvableData.Users.Any(x => x.Key == valueId)) | |||
{ | |||
var guildUser = data.guildMembers.FirstOrDefault(x => x.Key == valueId).Value; | |||
var guildUser = data.ResolvableData.GuildMembers.FirstOrDefault(x => x.Key == valueId).Value; | |||
if (guildUser != null) | |||
this.Value = guildUser; | |||
else | |||
this.Value = data.users.FirstOrDefault(x => x.Key == valueId).Value; | |||
this.Value = data.ResolvableData.Users.FirstOrDefault(x => x.Key == valueId).Value; | |||
} | |||
else if(data.roles.Any(x => x.Key == valueId)) | |||
else if(data.ResolvableData.Roles.Any(x => x.Key == valueId)) | |||
{ | |||
this.Value = data.roles.FirstOrDefault(x => x.Key == valueId).Value; | |||
this.Value = data.ResolvableData.Roles.FirstOrDefault(x => x.Key == valueId).Value; | |||
} | |||
} | |||
break; | |||
@@ -125,6 +125,8 @@ namespace Discord.WebSocket | |||
public static explicit operator string(SocketSlashCommandDataOption option) | |||
=> option.Value.ToString(); | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionDataOption.Options => this.Options; | |||
// IApplicationCommandInteractionDataOption | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionDataOption.Options | |||
=> this.Options; | |||
} | |||
} |
@@ -10,7 +10,7 @@ using Model = Discord.API.Interaction; | |||
namespace Discord.WebSocket | |||
{ | |||
/// <summary> | |||
/// Base class for User, Message, and Slash command interactions | |||
/// Base class for User, Message, and Slash command interactions | |||
/// </summary> | |||
public class SocketCommandBase : SocketInteraction | |||
{ | |||
@@ -8,123 +8,28 @@ namespace Discord.WebSocket | |||
/// <summary> | |||
/// Represents the base data tied with the <see cref="SocketCommandBase"/> interaction. | |||
/// </summary> | |||
public class SocketCommandBaseData : SocketEntity<ulong>, IApplicationCommandInteractionData | |||
public class SocketCommandBaseData<TOption> : SocketEntity<ulong>, IApplicationCommandInteractionData where TOption : IApplicationCommandInteractionDataOption | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <summary> | |||
/// The <see cref="SocketCommandBaseDataOption"/>'s received with this interaction. | |||
/// The <typeparamref name="TOption"/> received with this interaction. | |||
/// </summary> | |||
public IReadOnlyCollection<SocketCommandBaseDataOption> Options { get; private set; } | |||
internal Dictionary<ulong, SocketGuildUser> guildMembers { get; private set; } | |||
= new Dictionary<ulong, SocketGuildUser>(); | |||
internal Dictionary<ulong, SocketGlobalUser> users { get; private set; } | |||
= new Dictionary<ulong, SocketGlobalUser>(); | |||
internal Dictionary<ulong, SocketChannel> channels { get; private set; } | |||
= new Dictionary<ulong, SocketChannel>(); | |||
internal Dictionary<ulong, SocketRole> roles { get; private set; } | |||
= new Dictionary<ulong, SocketRole>(); | |||
private ulong? guildId; | |||
public virtual IReadOnlyCollection<TOption> Options { get; internal set; } | |||
internal SocketMessage Message { get; private set; } | |||
internal readonly SocketResolvableData<Model> ResolvableData; | |||
private ApplicationCommandType Type { get; set; } | |||
internal SocketCommandBaseData(DiscordSocketClient client, Model model, ulong? guildId) | |||
: base(client, model.Id) | |||
{ | |||
this.guildId = guildId; | |||
this.Type = (ApplicationCommandType)model.Type; | |||
this.Type = model.Type; | |||
if (model.Resolved.IsSpecified) | |||
{ | |||
var guild = this.guildId.HasValue ? Discord.GetGuild(this.guildId.Value) : null; | |||
var resolved = model.Resolved.Value; | |||
if (resolved.Users.IsSpecified) | |||
{ | |||
foreach (var user in resolved.Users.Value) | |||
{ | |||
var socketUser = Discord.GetOrCreateUser(this.Discord.State, user.Value); | |||
this.users.Add(ulong.Parse(user.Key), socketUser); | |||
} | |||
} | |||
if (resolved.Channels.IsSpecified) | |||
{ | |||
foreach (var channel in resolved.Channels.Value) | |||
{ | |||
SocketChannel socketChannel = guild != null | |||
? guild.GetChannel(channel.Value.Id) | |||
: Discord.GetChannel(channel.Value.Id); | |||
if (socketChannel == null) | |||
{ | |||
var channelModel = guild != null | |||
? Discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult() | |||
: Discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult(); | |||
socketChannel = guild != null | |||
? SocketGuildChannel.Create(guild, Discord.State, channelModel) | |||
: (SocketChannel)SocketChannel.CreatePrivate(Discord, Discord.State, channelModel); | |||
} | |||
Discord.State.AddChannel(socketChannel); | |||
this.channels.Add(ulong.Parse(channel.Key), socketChannel); | |||
} | |||
} | |||
if (resolved.Members.IsSpecified) | |||
{ | |||
foreach (var member in resolved.Members.Value) | |||
{ | |||
member.Value.User = resolved.Users.Value[member.Key]; | |||
var user = guild.AddOrUpdateUser(member.Value); | |||
this.guildMembers.Add(ulong.Parse(member.Key), user); | |||
} | |||
} | |||
if (resolved.Roles.IsSpecified) | |||
{ | |||
foreach (var role in resolved.Roles.Value) | |||
{ | |||
var socketRole = guild.AddOrUpdateRole(role.Value); | |||
this.roles.Add(ulong.Parse(role.Key), socketRole); | |||
} | |||
} | |||
if (resolved.Messages.IsSpecified) | |||
{ | |||
foreach (var msg in resolved.Messages.Value) | |||
{ | |||
var channel = client.GetChannel(msg.Value.ChannelId) as ISocketMessageChannel; | |||
SocketUser author; | |||
if (guild != null) | |||
{ | |||
if (msg.Value.WebhookId.IsSpecified) | |||
author = SocketWebhookUser.Create(guild, client.State, msg.Value.Author.Value, msg.Value.WebhookId.Value); | |||
else | |||
author = guild.GetUser(msg.Value.Author.Value.Id); | |||
} | |||
else | |||
author = (channel as SocketChannel).GetUser(msg.Value.Author.Value.Id); | |||
if (channel == null) | |||
{ | |||
if (!msg.Value.GuildId.IsSpecified) // assume it is a DM | |||
{ | |||
channel = client.CreateDMChannel(msg.Value.ChannelId, msg.Value.Author.Value, client.State); | |||
} | |||
} | |||
this.Message = SocketMessage.Create(client, client.State, author, channel, msg.Value); | |||
} | |||
} | |||
ResolvableData = new SocketResolvableData<Model>(client, guildId, model); | |||
} | |||
} | |||
@@ -135,15 +40,21 @@ namespace Discord.WebSocket | |||
return entity; | |||
} | |||
internal void Update(Model model) | |||
internal virtual void Update(Model model) | |||
{ | |||
this.Name = model.Name; | |||
this.Options = model.Options.IsSpecified | |||
? model.Options.Value.Select(x => new SocketCommandBaseDataOption(this, x)).ToImmutableArray() | |||
: null; | |||
} | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionData.Options => Options; | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionData.Options | |||
=> (IReadOnlyCollection<IApplicationCommandInteractionDataOption>)Options; | |||
} | |||
/// <summary> | |||
/// Represents the base data tied with the <see cref="SocketCommandBase"/> interaction. | |||
/// </summary> | |||
public class SocketCommandBaseData : SocketCommandBaseData<IApplicationCommandInteractionDataOption> | |||
{ | |||
internal SocketCommandBaseData(DiscordSocketClient client, Model model, ulong? guildId) | |||
: base(client, model, guildId) { } | |||
} | |||
} |
@@ -1,134 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Collections.Immutable; | |||
using System.Linq; | |||
using System.Reflection; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using Model = Discord.API.ApplicationCommandInteractionDataOption; | |||
namespace Discord.WebSocket | |||
{ | |||
/// <summary> | |||
/// Represents the base Websocket-based <see cref="IApplicationCommandInteractionDataOption"/> recieved by the gateway | |||
/// </summary> | |||
public class SocketCommandBaseDataOption : IApplicationCommandInteractionDataOption | |||
{ | |||
/// <inheritdoc/> | |||
public string Name { get; private set; } | |||
/// <inheritdoc/> | |||
public object Value { get; private set; } | |||
/// <inheritdoc/> | |||
public ApplicationCommandOptionType Type { get; private set; } | |||
/// <summary> | |||
/// The sub command options received for this sub command group. | |||
/// </summary> | |||
public IReadOnlyCollection<IApplicationCommandInteractionDataOption> Options { get; private set; } | |||
internal SocketCommandBaseDataOption() { } | |||
internal SocketCommandBaseDataOption(SocketCommandBaseData data, Model model) | |||
{ | |||
this.Name = model.Name; | |||
this.Type = model.Type; | |||
if (model.Value.IsSpecified) | |||
{ | |||
switch (Type) | |||
{ | |||
case ApplicationCommandOptionType.User: | |||
case ApplicationCommandOptionType.Role: | |||
case ApplicationCommandOptionType.Channel: | |||
case ApplicationCommandOptionType.Mentionable: | |||
if (ulong.TryParse($"{model.Value.Value}", out var valueId)) | |||
{ | |||
switch (this.Type) | |||
{ | |||
case ApplicationCommandOptionType.User: | |||
{ | |||
var guildUser = data.guildMembers.FirstOrDefault(x => x.Key == valueId).Value; | |||
if (guildUser != null) | |||
this.Value = guildUser; | |||
else | |||
this.Value = data.users.FirstOrDefault(x => x.Key == valueId).Value; | |||
} | |||
break; | |||
case ApplicationCommandOptionType.Channel: | |||
this.Value = data.channels.FirstOrDefault(x => x.Key == valueId).Value; | |||
break; | |||
case ApplicationCommandOptionType.Role: | |||
this.Value = data.roles.FirstOrDefault(x => x.Key == valueId).Value; | |||
break; | |||
case ApplicationCommandOptionType.Mentionable: | |||
{ | |||
if (data.guildMembers.Any(x => x.Key == valueId) || data.users.Any(x => x.Key == valueId)) | |||
{ | |||
var guildUser = data.guildMembers.FirstOrDefault(x => x.Key == valueId).Value; | |||
if (guildUser != null) | |||
this.Value = guildUser; | |||
else | |||
this.Value = data.users.FirstOrDefault(x => x.Key == valueId).Value; | |||
} | |||
else if (data.roles.Any(x => x.Key == valueId)) | |||
{ | |||
this.Value = data.roles.FirstOrDefault(x => x.Key == valueId).Value; | |||
} | |||
} | |||
break; | |||
default: | |||
this.Value = model.Value.Value; | |||
break; | |||
} | |||
} | |||
break; | |||
case ApplicationCommandOptionType.String: | |||
this.Value = model.Value.ToString(); | |||
break; | |||
case ApplicationCommandOptionType.Integer: | |||
{ | |||
if (model.Value.Value is int val) | |||
this.Value = val; | |||
else if (int.TryParse(model.Value.Value.ToString(), out int res)) | |||
this.Value = res; | |||
} | |||
break; | |||
case ApplicationCommandOptionType.Boolean: | |||
{ | |||
if (model.Value.Value is bool val) | |||
this.Value = val; | |||
else if (bool.TryParse(model.Value.Value.ToString(), out bool res)) | |||
this.Value = res; | |||
} | |||
break; | |||
case ApplicationCommandOptionType.Number: | |||
{ | |||
if (model.Value.Value is int val) | |||
this.Value = val; | |||
else if (double.TryParse(model.Value.Value.ToString(), out double res)) | |||
this.Value = res; | |||
} | |||
break; | |||
} | |||
} | |||
this.Options = model.Options.IsSpecified | |||
? model.Options.Value.Select(x => new SocketCommandBaseDataOption(data, x)).ToImmutableArray() | |||
: null; | |||
} | |||
// Converters | |||
public static explicit operator bool(SocketCommandBaseDataOption option) | |||
=> (bool)option.Value; | |||
public static explicit operator int(SocketCommandBaseDataOption option) | |||
=> (int)option.Value; | |||
public static explicit operator string(SocketCommandBaseDataOption option) | |||
=> option.Value.ToString(); | |||
IReadOnlyCollection<IApplicationCommandInteractionDataOption> IApplicationCommandInteractionDataOption.Options => this.Options; | |||
} | |||
} |
@@ -0,0 +1,113 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace Discord.WebSocket | |||
{ | |||
internal class SocketResolvableData<T> where T : API.IResolvable | |||
{ | |||
internal readonly Dictionary<ulong, SocketGuildUser> GuildMembers | |||
= new Dictionary<ulong, SocketGuildUser>(); | |||
internal readonly Dictionary<ulong, SocketGlobalUser> Users | |||
= new Dictionary<ulong, SocketGlobalUser>(); | |||
internal readonly Dictionary<ulong, SocketChannel> Channels | |||
= new Dictionary<ulong, SocketChannel>(); | |||
internal readonly Dictionary<ulong, SocketRole> Roles | |||
= new Dictionary<ulong, SocketRole>(); | |||
internal readonly Dictionary<ulong, SocketMessage> Messages | |||
= new Dictionary<ulong, SocketMessage>(); | |||
internal SocketResolvableData(DiscordSocketClient discord, ulong? guildId, T model) | |||
{ | |||
var guild = guildId.HasValue ? discord.GetGuild(guildId.Value) : null; | |||
var resolved = model.Resolved.Value; | |||
if (resolved.Users.IsSpecified) | |||
{ | |||
foreach (var user in resolved.Users.Value) | |||
{ | |||
var socketUser = discord.GetOrCreateUser(discord.State, user.Value); | |||
this.Users.Add(ulong.Parse(user.Key), socketUser); | |||
} | |||
} | |||
if (resolved.Channels.IsSpecified) | |||
{ | |||
foreach (var channel in resolved.Channels.Value) | |||
{ | |||
SocketChannel socketChannel = guild != null | |||
? guild.GetChannel(channel.Value.Id) | |||
: discord.GetChannel(channel.Value.Id); | |||
if (socketChannel == null) | |||
{ | |||
var channelModel = guild != null | |||
? discord.Rest.ApiClient.GetChannelAsync(guild.Id, channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult() | |||
: discord.Rest.ApiClient.GetChannelAsync(channel.Value.Id).ConfigureAwait(false).GetAwaiter().GetResult(); | |||
socketChannel = guild != null | |||
? SocketGuildChannel.Create(guild, discord.State, channelModel) | |||
: (SocketChannel)SocketChannel.CreatePrivate(discord, discord.State, channelModel); | |||
} | |||
discord.State.AddChannel(socketChannel); | |||
this.Channels.Add(ulong.Parse(channel.Key), socketChannel); | |||
} | |||
} | |||
if (resolved.Members.IsSpecified) | |||
{ | |||
foreach (var member in resolved.Members.Value) | |||
{ | |||
member.Value.User = resolved.Users.Value[member.Key]; | |||
var user = guild.AddOrUpdateUser(member.Value); | |||
this.GuildMembers.Add(ulong.Parse(member.Key), user); | |||
} | |||
} | |||
if (resolved.Roles.IsSpecified) | |||
{ | |||
foreach (var role in resolved.Roles.Value) | |||
{ | |||
var socketRole = guild.AddOrUpdateRole(role.Value); | |||
this.Roles.Add(ulong.Parse(role.Key), socketRole); | |||
} | |||
} | |||
if (resolved.Messages.IsSpecified) | |||
{ | |||
foreach (var msg in resolved.Messages.Value) | |||
{ | |||
var channel = discord.GetChannel(msg.Value.ChannelId) as ISocketMessageChannel; | |||
SocketUser author; | |||
if (guild != null) | |||
{ | |||
if (msg.Value.WebhookId.IsSpecified) | |||
author = SocketWebhookUser.Create(guild, discord.State, msg.Value.Author.Value, msg.Value.WebhookId.Value); | |||
else | |||
author = guild.GetUser(msg.Value.Author.Value.Id); | |||
} | |||
else | |||
author = (channel as SocketChannel).GetUser(msg.Value.Author.Value.Id); | |||
if (channel == null) | |||
{ | |||
if (!msg.Value.GuildId.IsSpecified) // assume it is a DM | |||
{ | |||
channel = discord.CreateDMChannel(msg.Value.ChannelId, msg.Value.Author.Value, discord.State); | |||
} | |||
} | |||
var message = SocketMessage.Create(discord, discord.State, author, channel, msg.Value); | |||
this.Messages.Add(message.Id, message); | |||
} | |||
} | |||
} | |||
} | |||
} |