@@ -21,5 +21,10 @@ namespace Discord | |||||
/// Gets or sets the embed the message should display. | /// Gets or sets the embed the message should display. | ||||
/// </summary> | /// </summary> | ||||
public Optional<Embed> Embed { get; set; } | public Optional<Embed> Embed { get; set; } | ||||
/// <summary> | |||||
/// Gets or sets the components for this message. | |||||
/// </summary> | |||||
public Optional<MessageComponent> Components { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,4 +1,4 @@ | |||||
#pragma warning disable CS1591 | |||||
#pragma warning disable CS1591 | |||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
namespace Discord.API.Rest | namespace Discord.API.Rest | ||||
@@ -10,5 +10,7 @@ namespace Discord.API.Rest | |||||
public Optional<string> Content { get; set; } | public Optional<string> Content { get; set; } | ||||
[JsonProperty("embed")] | [JsonProperty("embed")] | ||||
public Optional<Embed> Embed { get; set; } | public Optional<Embed> Embed { get; set; } | ||||
[JsonProperty("components")] | |||||
public Optional<API.ActionRowComponent[]> Components { get; set; } | |||||
} | } | ||||
} | } |
@@ -41,7 +41,8 @@ namespace Discord.Rest | |||||
var apiArgs = new API.Rest.ModifyMessageParams | var apiArgs = new API.Rest.ModifyMessageParams | ||||
{ | { | ||||
Content = args.Content, | Content = args.Content, | ||||
Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>() | |||||
Embed = args.Embed.IsSpecified ? args.Embed.Value.ToModel() : Optional.Create<API.Embed>(), | |||||
Components = args?.Components.GetValueOrDefault()?.Components.Select(x => new API.ActionRowComponent(x)).ToArray() ?? Optional<API.ActionRowComponent[]>.Unspecified | |||||
}; | }; | ||||
return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false); | return await client.ApiClient.ModifyMessageAsync(msg.Channel.Id, msg.Id, apiArgs, options).ConfigureAwait(false); | ||||
} | } | ||||
@@ -13,6 +13,9 @@ namespace Discord.API.Gateway | |||||
[JsonProperty("id")] | [JsonProperty("id")] | ||||
public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
[JsonProperty("application_id")] | |||||
public ulong ApplicationId { get; set; } | |||||
[JsonProperty("type")] | [JsonProperty("type")] | ||||
public InteractionType Type { get; set; } | public InteractionType Type { get; set; } | ||||
@@ -20,18 +23,25 @@ namespace Discord.API.Gateway | |||||
public Optional<object> Data { get; set; } | public Optional<object> Data { get; set; } | ||||
[JsonProperty("guild_id")] | [JsonProperty("guild_id")] | ||||
public ulong GuildId { get; set; } | |||||
public Optional<ulong> GuildId { get; set; } | |||||
[JsonProperty("channel_id")] | [JsonProperty("channel_id")] | ||||
public ulong ChannelId { get; set; } | |||||
public Optional<ulong> ChannelId { get; set; } | |||||
[JsonProperty("member")] | [JsonProperty("member")] | ||||
public GuildMember Member { get; set; } | |||||
public Optional<GuildMember> Member { get; set; } | |||||
[JsonProperty("user")] | |||||
public Optional<User> User { get; set; } | |||||
[JsonProperty("token")] | [JsonProperty("token")] | ||||
public string Token { get; set; } | public string Token { get; set; } | ||||
[JsonProperty("version")] | [JsonProperty("version")] | ||||
public int Version { get; set; } | public int Version { get; set; } | ||||
[JsonProperty("message")] | |||||
public Optional<Message> Message { get; set; } | |||||
} | } | ||||
} | } |
@@ -1785,26 +1785,33 @@ namespace Discord.WebSocket | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<API.Gateway.InteractionCreated>(_serializer); | var data = (payload as JToken).ToObject<API.Gateway.InteractionCreated>(_serializer); | ||||
if (State.GetChannel(data.ChannelId) is SocketGuildChannel channel) | |||||
if (data.Member.IsSpecified && data.ChannelId.IsSpecified) | |||||
{ | { | ||||
var guild = channel.Guild; | |||||
if (!guild.IsSynced) | |||||
if (State.GetChannel(data.ChannelId.Value) is SocketGuildChannel channel) | |||||
{ | { | ||||
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false); | |||||
return; | |||||
} | |||||
var guild = channel.Guild; | |||||
if (!guild.IsSynced) | |||||
{ | |||||
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false); | |||||
return; | |||||
} | |||||
var interaction = SocketInteraction.Create(this, data); | |||||
var interaction = SocketInteraction.Create(this, data); | |||||
if (this.AlwaysAcknowledgeInteractions) | |||||
await interaction.AcknowledgeAsync().ConfigureAwait(false); | |||||
if (this.AlwaysAcknowledgeInteractions) | |||||
await interaction.AcknowledgeAsync().ConfigureAwait(false); | |||||
await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false); | |||||
await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false); | |||||
} | |||||
else | |||||
{ | |||||
await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false); | |||||
return; | |||||
} | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false); | |||||
return; | |||||
// DM TODO | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
@@ -14,6 +14,8 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
new public SocketMessageComponentData Data { get; } | new public SocketMessageComponentData Data { get; } | ||||
public SocketMessage Message { get; private set; } | |||||
internal SocketMessageComponent(DiscordSocketClient client, Model model) | internal SocketMessageComponent(DiscordSocketClient client, Model model) | ||||
: base(client, model.Id) | : base(client, model.Id) | ||||
{ | { | ||||
@@ -22,6 +24,8 @@ namespace Discord.WebSocket | |||||
: null; | : null; | ||||
this.Data = new SocketMessageComponentData(dataModel); | this.Data = new SocketMessageComponentData(dataModel); | ||||
} | } | ||||
new internal static SocketMessageComponent Create(DiscordSocketClient client, Model model) | new internal static SocketMessageComponent Create(DiscordSocketClient client, Model model) | ||||
@@ -31,6 +35,23 @@ namespace Discord.WebSocket | |||||
return entity; | return entity; | ||||
} | } | ||||
internal override void Update(Model model) | |||||
{ | |||||
base.Update(model); | |||||
if (model.Message.IsSpecified) | |||||
{ | |||||
if (this.Message == null) | |||||
{ | |||||
this.Message = SocketMessage.Create(this.Discord, this.Discord.State, this.User, this.Channel, model.Message.Value); | |||||
} | |||||
else | |||||
{ | |||||
this.Message.Update(this.Discord.State, model.Message.Value); | |||||
} | |||||
} | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Responds to an Interaction. | /// Responds to an Interaction. | ||||
/// <para> | /// <para> | ||||
@@ -24,7 +24,7 @@ namespace Discord.WebSocket | |||||
(model.Data.Value as JToken).ToObject<DataModel>() | (model.Data.Value as JToken).ToObject<DataModel>() | ||||
: null; | : null; | ||||
Data = SocketSlashCommandData.Create(client, dataModel, model.GuildId); | |||||
Data = SocketSlashCommandData.Create(client, dataModel, model.Id); | |||||
} | } | ||||
new internal static SocketInteraction Create(DiscordSocketClient client, Model model) | new internal static SocketInteraction Create(DiscordSocketClient client, Model model) | ||||
@@ -40,7 +40,7 @@ namespace Discord.WebSocket | |||||
(model.Data.Value as JToken).ToObject<DataModel>() | (model.Data.Value as JToken).ToObject<DataModel>() | ||||
: null; | : null; | ||||
this.Data.Update(data, this.Guild.Id); | |||||
this.Data.Update(data); | |||||
base.Update(model); | base.Update(model); | ||||
} | } | ||||
@@ -18,27 +18,23 @@ namespace Discord.WebSocket | |||||
/// </summary> | /// </summary> | ||||
public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | ||||
private ulong guildId; | |||||
internal SocketSlashCommandData(DiscordSocketClient client, ulong id) | internal SocketSlashCommandData(DiscordSocketClient client, ulong id) | ||||
: base(client, id) | : base(client, id) | ||||
{ | { | ||||
} | } | ||||
internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong guildId) | |||||
internal static SocketSlashCommandData Create(DiscordSocketClient client, Model model, ulong id) | |||||
{ | { | ||||
var entity = new SocketSlashCommandData(client, model.Id); | var entity = new SocketSlashCommandData(client, model.Id); | ||||
entity.Update(model, guildId); | |||||
entity.Update(model); | |||||
return entity; | return entity; | ||||
} | } | ||||
internal void Update(Model model, ulong guildId) | |||||
internal void Update(Model model) | |||||
{ | { | ||||
this.Name = model.Name; | this.Name = model.Name; | ||||
this.guildId = guildId; | |||||
this.Options = model.Options.IsSpecified | this.Options = model.Options.IsSpecified | ||||
? model.Options.Value.Select(x => new SocketSlashCommandDataOption(x, this.Discord, guildId)).ToImmutableArray() | |||||
? model.Options.Value.Select(x => new SocketSlashCommandDataOption(x, this.Discord)).ToImmutableArray() | |||||
: null; | : null; | ||||
} | } | ||||
@@ -25,18 +25,16 @@ namespace Discord.WebSocket | |||||
public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | ||||
private DiscordSocketClient discord; | private DiscordSocketClient discord; | ||||
private ulong guild; | |||||
internal SocketSlashCommandDataOption() { } | internal SocketSlashCommandDataOption() { } | ||||
internal SocketSlashCommandDataOption(Model model, DiscordSocketClient discord, ulong guild) | |||||
internal SocketSlashCommandDataOption(Model model, DiscordSocketClient discord) | |||||
{ | { | ||||
this.Name = model.Name; | this.Name = model.Name; | ||||
this.Value = model.Value.IsSpecified ? model.Value.Value : null; | this.Value = model.Value.IsSpecified ? model.Value.Value : null; | ||||
this.discord = discord; | this.discord = discord; | ||||
this.guild = guild; | |||||
this.Options = model.Options.IsSpecified | this.Options = model.Options.IsSpecified | ||||
? model.Options.Value.Select(x => new SocketSlashCommandDataOption(x, discord, guild)).ToImmutableArray() | |||||
? model.Options.Value.Select(x => new SocketSlashCommandDataOption(x, discord)).ToImmutableArray() | |||||
: null; | : null; | ||||
} | } | ||||
@@ -52,7 +50,7 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
if (option.Value is ulong id) | if (option.Value is ulong id) | ||||
{ | { | ||||
var guild = option.discord.GetGuild(option.guild); | |||||
var guild = option.discord.GetGuild(id); | |||||
if (guild == null) | if (guild == null) | ||||
return null; | return null; | ||||
@@ -67,7 +65,7 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
if (option.Value is ulong id) | if (option.Value is ulong id) | ||||
{ | { | ||||
var guild = option.discord.GetGuild(option.guild); | |||||
var guild = option.discord.GetGuild(id); | |||||
if (guild == null) | if (guild == null) | ||||
return null; | return null; | ||||
@@ -82,7 +80,7 @@ namespace Discord.WebSocket | |||||
{ | { | ||||
if(option.Value is ulong id) | if(option.Value is ulong id) | ||||
{ | { | ||||
var guild = option.discord.GetGuild(option.guild); | |||||
var guild = option.discord.GetGuild(id); | |||||
if (guild == null) | if (guild == null) | ||||
return null; | return null; | ||||
@@ -14,21 +14,14 @@ namespace Discord.WebSocket | |||||
public abstract class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction | public abstract class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// The <see cref="SocketGuild"/> this interaction was used in. | |||||
/// The <see cref="ISocketMessageChannel"/> this interaction was used in. | |||||
/// </summary> | /// </summary> | ||||
public SocketGuild Guild | |||||
=> Discord.GetGuild(GuildId); | |||||
public ISocketMessageChannel Channel { get; private set; } | |||||
/// <summary> | /// <summary> | ||||
/// The <see cref="SocketTextChannel"/> this interaction was used in. | |||||
/// The <see cref="SocketUser"/> who triggered this interaction. | |||||
/// </summary> | /// </summary> | ||||
public SocketTextChannel Channel | |||||
=> Guild.GetTextChannel(ChannelId); | |||||
/// <summary> | |||||
/// The <see cref="SocketGuildUser"/> who triggered this interaction. | |||||
/// </summary> | |||||
public SocketGuildUser User { get; private set; } | |||||
public SocketUser User { get; private set; } | |||||
/// <summary> | /// <summary> | ||||
/// The type of this interaction. | /// The type of this interaction. | ||||
@@ -58,9 +51,8 @@ namespace Discord.WebSocket | |||||
public bool IsValidToken | public bool IsValidToken | ||||
=> CheckToken(); | => CheckToken(); | ||||
private ulong GuildId { get; set; } | |||||
private ulong ChannelId { get; set; } | |||||
private ulong UserId { get; set; } | |||||
private ulong? GuildId { get; set; } | |||||
private ulong? ChannelId { get; set; } | |||||
internal SocketInteraction(DiscordSocketClient client, ulong id) | internal SocketInteraction(DiscordSocketClient client, ulong id) | ||||
: base(client, id) | : base(client, id) | ||||
@@ -83,15 +75,35 @@ namespace Discord.WebSocket | |||||
? model.Data.Value | ? model.Data.Value | ||||
: null; | : null; | ||||
this.GuildId = model.GuildId; | |||||
this.ChannelId = model.ChannelId; | |||||
this.GuildId = model.GuildId.ToNullable(); | |||||
this.ChannelId = model.ChannelId.ToNullable(); | |||||
this.Token = model.Token; | this.Token = model.Token; | ||||
this.Version = model.Version; | this.Version = model.Version; | ||||
this.UserId = model.Member.User.Id; | |||||
this.Type = model.Type; | this.Type = model.Type; | ||||
if (this.User == null) | if (this.User == null) | ||||
this.User = SocketGuildUser.Create(this.Guild, Discord.State, model.Member); // Change from getter. | |||||
{ | |||||
if (model.Member.IsSpecified && model.GuildId.IsSpecified) | |||||
{ | |||||
this.User = SocketGuildUser.Create(Discord.State.GetGuild(this.GuildId.Value), Discord.State, model.Member.Value); | |||||
} | |||||
else | |||||
{ | |||||
this.User = SocketGlobalUser.Create(this.Discord, this.Discord.State, model.User.Value); | |||||
} | |||||
} | |||||
if (this.Channel == null) | |||||
{ | |||||
if (model.ChannelId.IsSpecified) | |||||
{ | |||||
this.Channel = Discord.State.GetChannel(model.ChannelId.Value) as ISocketMessageChannel; | |||||
} | |||||
else | |||||
{ | |||||
this.Channel = Discord.State.GetDMChannel(this.User.Id); | |||||
} | |||||
} | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||