| @@ -21,5 +21,10 @@ namespace Discord | |||
| /// Gets or sets the embed the message should display. | |||
| /// </summary> | |||
| 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; | |||
| namespace Discord.API.Rest | |||
| @@ -10,5 +10,7 @@ namespace Discord.API.Rest | |||
| public Optional<string> Content { get; set; } | |||
| [JsonProperty("embed")] | |||
| 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 | |||
| { | |||
| 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); | |||
| } | |||
| @@ -13,6 +13,9 @@ namespace Discord.API.Gateway | |||
| [JsonProperty("id")] | |||
| public ulong Id { get; set; } | |||
| [JsonProperty("application_id")] | |||
| public ulong ApplicationId { get; set; } | |||
| [JsonProperty("type")] | |||
| public InteractionType Type { get; set; } | |||
| @@ -20,18 +23,25 @@ namespace Discord.API.Gateway | |||
| public Optional<object> Data { get; set; } | |||
| [JsonProperty("guild_id")] | |||
| public ulong GuildId { get; set; } | |||
| public Optional<ulong> GuildId { get; set; } | |||
| [JsonProperty("channel_id")] | |||
| public ulong ChannelId { get; set; } | |||
| public Optional<ulong> ChannelId { get; set; } | |||
| [JsonProperty("member")] | |||
| public GuildMember Member { get; set; } | |||
| public Optional<GuildMember> Member { get; set; } | |||
| [JsonProperty("user")] | |||
| public Optional<User> User { get; set; } | |||
| [JsonProperty("token")] | |||
| public string Token { get; set; } | |||
| [JsonProperty("version")] | |||
| 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); | |||
| 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 | |||
| { | |||
| await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false); | |||
| return; | |||
| // DM TODO | |||
| } | |||
| } | |||
| break; | |||
| @@ -14,6 +14,8 @@ namespace Discord.WebSocket | |||
| { | |||
| new public SocketMessageComponentData Data { get; } | |||
| public SocketMessage Message { get; private set; } | |||
| internal SocketMessageComponent(DiscordSocketClient client, Model model) | |||
| : base(client, model.Id) | |||
| { | |||
| @@ -22,6 +24,8 @@ namespace Discord.WebSocket | |||
| : null; | |||
| this.Data = new SocketMessageComponentData(dataModel); | |||
| } | |||
| new internal static SocketMessageComponent Create(DiscordSocketClient client, Model model) | |||
| @@ -31,6 +35,23 @@ namespace Discord.WebSocket | |||
| 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> | |||
| /// Responds to an Interaction. | |||
| /// <para> | |||
| @@ -24,7 +24,7 @@ namespace Discord.WebSocket | |||
| (model.Data.Value as JToken).ToObject<DataModel>() | |||
| : null; | |||
| Data = SocketSlashCommandData.Create(client, dataModel, model.GuildId); | |||
| Data = SocketSlashCommandData.Create(client, dataModel, model.Id); | |||
| } | |||
| new internal static SocketInteraction Create(DiscordSocketClient client, Model model) | |||
| @@ -40,7 +40,7 @@ namespace Discord.WebSocket | |||
| (model.Data.Value as JToken).ToObject<DataModel>() | |||
| : null; | |||
| this.Data.Update(data, this.Guild.Id); | |||
| this.Data.Update(data); | |||
| base.Update(model); | |||
| } | |||
| @@ -18,27 +18,23 @@ namespace Discord.WebSocket | |||
| /// </summary> | |||
| public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | |||
| private ulong guildId; | |||
| internal SocketSlashCommandData(DiscordSocketClient client, ulong 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); | |||
| entity.Update(model, guildId); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal void Update(Model model, ulong guildId) | |||
| internal void Update(Model model) | |||
| { | |||
| this.Name = model.Name; | |||
| this.guildId = guildId; | |||
| 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; | |||
| } | |||
| @@ -25,18 +25,16 @@ namespace Discord.WebSocket | |||
| public IReadOnlyCollection<SocketSlashCommandDataOption> Options { get; private set; } | |||
| private DiscordSocketClient discord; | |||
| private ulong guild; | |||
| internal SocketSlashCommandDataOption() { } | |||
| internal SocketSlashCommandDataOption(Model model, DiscordSocketClient discord, ulong guild) | |||
| internal SocketSlashCommandDataOption(Model model, DiscordSocketClient discord) | |||
| { | |||
| this.Name = model.Name; | |||
| this.Value = model.Value.IsSpecified ? model.Value.Value : null; | |||
| this.discord = discord; | |||
| this.guild = guild; | |||
| 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; | |||
| } | |||
| @@ -52,7 +50,7 @@ namespace Discord.WebSocket | |||
| { | |||
| if (option.Value is ulong id) | |||
| { | |||
| var guild = option.discord.GetGuild(option.guild); | |||
| var guild = option.discord.GetGuild(id); | |||
| if (guild == null) | |||
| return null; | |||
| @@ -67,7 +65,7 @@ namespace Discord.WebSocket | |||
| { | |||
| if (option.Value is ulong id) | |||
| { | |||
| var guild = option.discord.GetGuild(option.guild); | |||
| var guild = option.discord.GetGuild(id); | |||
| if (guild == null) | |||
| return null; | |||
| @@ -82,7 +80,7 @@ namespace Discord.WebSocket | |||
| { | |||
| if(option.Value is ulong id) | |||
| { | |||
| var guild = option.discord.GetGuild(option.guild); | |||
| var guild = option.discord.GetGuild(id); | |||
| if (guild == null) | |||
| return null; | |||
| @@ -14,21 +14,14 @@ namespace Discord.WebSocket | |||
| public abstract class SocketInteraction : SocketEntity<ulong>, IDiscordInteraction | |||
| { | |||
| /// <summary> | |||
| /// The <see cref="SocketGuild"/> this interaction was used in. | |||
| /// The <see cref="ISocketMessageChannel"/> this interaction was used in. | |||
| /// </summary> | |||
| public SocketGuild Guild | |||
| => Discord.GetGuild(GuildId); | |||
| public ISocketMessageChannel Channel { get; private set; } | |||
| /// <summary> | |||
| /// The <see cref="SocketTextChannel"/> this interaction was used in. | |||
| /// The <see cref="SocketUser"/> who triggered this interaction. | |||
| /// </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> | |||
| /// The type of this interaction. | |||
| @@ -58,9 +51,8 @@ namespace Discord.WebSocket | |||
| public bool IsValidToken | |||
| => 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) | |||
| : base(client, id) | |||
| @@ -83,15 +75,35 @@ namespace Discord.WebSocket | |||
| ? model.Data.Value | |||
| : null; | |||
| this.GuildId = model.GuildId; | |||
| this.ChannelId = model.ChannelId; | |||
| this.GuildId = model.GuildId.ToNullable(); | |||
| this.ChannelId = model.ChannelId.ToNullable(); | |||
| this.Token = model.Token; | |||
| this.Version = model.Version; | |||
| this.UserId = model.Member.User.Id; | |||
| this.Type = model.Type; | |||
| 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> | |||