diff --git a/twilight-cache-inmemory/src/lib.rs b/twilight-cache-inmemory/src/lib.rs index 924af03ca38..ca855977e7a 100644 --- a/twilight-cache-inmemory/src/lib.rs +++ b/twilight-cache-inmemory/src/lib.rs @@ -918,6 +918,7 @@ impl UpdateCache for Event { | Event::ThreadMembersUpdate(_) | Event::ThreadMemberUpdate(_) | Event::TypingStart(_) + | Event::VoiceChannelEffectSend(_) | Event::VoiceServerUpdate(_) | Event::WebhooksUpdate(_) => {} } diff --git a/twilight-gateway/src/event.rs b/twilight-gateway/src/event.rs index 5fe1814e7dc..158d8a6b72a 100644 --- a/twilight-gateway/src/event.rs +++ b/twilight-gateway/src/event.rs @@ -184,12 +184,15 @@ bitflags! { const UNAVAILABLE_GUILD = 1 << 40; /// Current user's profile has been updated. const USER_UPDATE = 1 << 41; + /// A user has sent an effect to a voice channel the bot is in. + const VOICE_CHANNEL_EFFECT_SEND = 1 << 42; /// Voice server has provided an update with voice session details. - const VOICE_SERVER_UPDATE = 1 << 42; + const VOICE_SERVER_UPDATE = 1 << 43; /// User's state in a voice channel has been updated. - const VOICE_STATE_UPDATE = 1 << 43; + const VOICE_STATE_UPDATE = 1 << 44; /// Webhook in a guild has been updated. - const WEBHOOKS_UPDATE = 1 << 44; + const WEBHOOKS_UPDATE = 1 << 45; + /// All [`EventTypeFlags`] in [`Intents::AUTO_MODERATION_CONFIGURATION`]. /// @@ -316,7 +319,8 @@ bitflags! { /// All [`EventTypeFlags`] in [`Intents::GUILD_VOICE_STATES`]. /// /// [`Intents::GUILD_VOICE_STATES`]: crate::Intents::GUILD_VOICE_STATES - const GUILD_VOICE_STATES = Self::VOICE_STATE_UPDATE.bits(); + const GUILD_VOICE_STATES = Self::VOICE_STATE_UPDATE.bits() + | Self::VOICE_CHANNEL_EFFECT_SEND.bits(); /// All [`EventTypeFlags`] in [`Intents::GUILD_WEBHOOKS`]. /// @@ -396,6 +400,7 @@ impl From for EventTypeFlags { EventType::TypingStart => Self::TYPING_START, EventType::UnavailableGuild => Self::UNAVAILABLE_GUILD, EventType::UserUpdate => Self::USER_UPDATE, + EventType::VoiceChannelEffectSend => Self::VOICE_CHANNEL_EFFECT_SEND, EventType::VoiceServerUpdate => Self::VOICE_SERVER_UPDATE, EventType::VoiceStateUpdate => Self::VOICE_STATE_UPDATE, EventType::WebhooksUpdate => Self::WEBHOOKS_UPDATE, diff --git a/twilight-model/src/gateway/event/dispatch.rs b/twilight-model/src/gateway/event/dispatch.rs index d3722408406..59569764284 100644 --- a/twilight-model/src/gateway/event/dispatch.rs +++ b/twilight-model/src/gateway/event/dispatch.rs @@ -75,6 +75,7 @@ pub enum DispatchEvent { TypingStart(Box), UnavailableGuild(UnavailableGuild), UserUpdate(UserUpdate), + VoiceChannelEffectSend(Box), VoiceServerUpdate(VoiceServerUpdate), VoiceStateUpdate(Box), WebhooksUpdate(WebhooksUpdate), @@ -145,6 +146,7 @@ impl DispatchEvent { Self::TypingStart(_) => EventType::TypingStart, Self::UnavailableGuild(_) => EventType::UnavailableGuild, Self::UserUpdate(_) => EventType::UserUpdate, + Self::VoiceChannelEffectSend(_) => EventType::VoiceChannelEffectSend, Self::VoiceServerUpdate(_) => EventType::VoiceServerUpdate, Self::VoiceStateUpdate(_) => EventType::VoiceStateUpdate, Self::WebhooksUpdate(_) => EventType::WebhooksUpdate, @@ -217,6 +219,7 @@ impl TryFrom for DispatchEvent { Event::TypingStart(v) => Self::TypingStart(v), Event::UnavailableGuild(v) => Self::UnavailableGuild(v), Event::UserUpdate(v) => Self::UserUpdate(v), + Event::VoiceChannelEffectSend(v) => Self::VoiceChannelEffectSend(v), Event::VoiceServerUpdate(v) => Self::VoiceServerUpdate(v), Event::VoiceStateUpdate(v) => Self::VoiceStateUpdate(v), Event::WebhooksUpdate(v) => Self::WebhooksUpdate(v), @@ -421,6 +424,9 @@ impl<'de, 'a> DeserializeSeed<'de> for DispatchEventWithTypeDeserializer<'a> { DispatchEvent::TypingStart(Box::new(TypingStart::deserialize(deserializer)?)) } "USER_UPDATE" => DispatchEvent::UserUpdate(UserUpdate::deserialize(deserializer)?), + "VOICE_CHANNEL_EFFECT_SEND" => DispatchEvent::VoiceChannelEffectSend(Box::new( + VoiceChannelEffectSend::deserialize(deserializer)?, + )), "VOICE_SERVER_UPDATE" => { DispatchEvent::VoiceServerUpdate(VoiceServerUpdate::deserialize(deserializer)?) } diff --git a/twilight-model/src/gateway/event/kind.rs b/twilight-model/src/gateway/event/kind.rs index 7e03c9bc982..ebabd75b3cc 100644 --- a/twilight-model/src/gateway/event/kind.rs +++ b/twilight-model/src/gateway/event/kind.rs @@ -85,6 +85,7 @@ pub enum EventType { TypingStart, UnavailableGuild, UserUpdate, + VoiceChannelEffectSend, VoiceServerUpdate, VoiceStateUpdate, WebhooksUpdate, @@ -154,6 +155,7 @@ impl EventType { Self::TypingStart => Some("TYPING_START"), Self::UnavailableGuild => Some("UNAVAILABLE_GUILD"), Self::UserUpdate => Some("USER_UPDATE"), + Self::VoiceChannelEffectSend => Some("VOICE_CHANNEL_EFFECT_SEND"), Self::VoiceServerUpdate => Some("VOICE_SERVER_UPDATE"), Self::VoiceStateUpdate => Some("VOICE_STATE_UPDATE"), Self::WebhooksUpdate => Some("WEBHOOKS_UPDATE"), @@ -232,6 +234,7 @@ impl<'a> TryFrom<&'a str> for EventType { "TYPING_START" => Ok(Self::TypingStart), "UNAVAILABLE_GUILD" => Ok(Self::UnavailableGuild), "USER_UPDATE" => Ok(Self::UserUpdate), + "VOICE_CHANNEL_EFFECT_SEND" => Ok(Self::VoiceChannelEffectSend), "VOICE_SERVER_UPDATE" => Ok(Self::VoiceServerUpdate), "VOICE_STATE_UPDATE" => Ok(Self::VoiceStateUpdate), "WEBHOOKS_UPDATE" => Ok(Self::WebhooksUpdate), @@ -366,6 +369,10 @@ mod tests { assert_variant(EventType::TypingStart, "TYPING_START"); assert_variant(EventType::UnavailableGuild, "UNAVAILABLE_GUILD"); assert_variant(EventType::UserUpdate, "USER_UPDATE"); + assert_variant( + EventType::VoiceChannelEffectSend, + "VOICE_CHANNEL_EFFECT_SEND", + ); assert_variant(EventType::VoiceServerUpdate, "VOICE_SERVER_UPDATE"); assert_variant(EventType::VoiceStateUpdate, "VOICE_STATE_UPDATE"); assert_variant(EventType::WebhooksUpdate, "WEBHOOKS_UPDATE"); diff --git a/twilight-model/src/gateway/event/mod.rs b/twilight-model/src/gateway/event/mod.rs index 0a7d38b24dc..0f0377b8352 100644 --- a/twilight-model/src/gateway/event/mod.rs +++ b/twilight-model/src/gateway/event/mod.rs @@ -165,6 +165,8 @@ pub enum Event { UnavailableGuild(UnavailableGuild), /// The current user was updated. UserUpdate(UserUpdate), + /// A user sent an effect in a voice channel the bot is in. + VoiceChannelEffectSend(Box), /// A voice server update was sent. VoiceServerUpdate(VoiceServerUpdate), /// A voice state in a voice channel was updated. @@ -234,6 +236,7 @@ impl Event { Event::ThreadUpdate(e) => e.0.guild_id, Event::TypingStart(e) => e.guild_id, Event::UnavailableGuild(e) => Some(e.id), + Event::VoiceChannelEffectSend(e) => Some(e.guild_id), Event::VoiceServerUpdate(e) => Some(e.guild_id), Event::VoiceStateUpdate(e) => e.0.guild_id, Event::WebhooksUpdate(e) => Some(e.guild_id), @@ -325,6 +328,7 @@ impl Event { Self::TypingStart(_) => EventType::TypingStart, Self::UnavailableGuild(_) => EventType::UnavailableGuild, Self::UserUpdate(_) => EventType::UserUpdate, + Self::VoiceChannelEffectSend(_) => EventType::VoiceChannelEffectSend, Self::VoiceServerUpdate(_) => EventType::VoiceServerUpdate, Self::VoiceStateUpdate(_) => EventType::VoiceStateUpdate, Self::WebhooksUpdate(_) => EventType::WebhooksUpdate, @@ -400,6 +404,7 @@ impl From for Event { DispatchEvent::TypingStart(v) => Self::TypingStart(v), DispatchEvent::UnavailableGuild(v) => Self::UnavailableGuild(v), DispatchEvent::UserUpdate(v) => Self::UserUpdate(v), + DispatchEvent::VoiceChannelEffectSend(v) => Self::VoiceChannelEffectSend(v), DispatchEvent::VoiceServerUpdate(v) => Self::VoiceServerUpdate(v), DispatchEvent::VoiceStateUpdate(v) => Self::VoiceStateUpdate(v), DispatchEvent::WebhooksUpdate(v) => Self::WebhooksUpdate(v), @@ -506,6 +511,7 @@ mod tests { const_assert!(mem::size_of::() > EVENT_THRESHOLD); const_assert!(mem::size_of::() > EVENT_THRESHOLD); const_assert!(mem::size_of::() > EVENT_THRESHOLD); + const_assert!(mem::size_of::() > EVENT_THRESHOLD); const_assert!(mem::size_of::() > EVENT_THRESHOLD); // Unboxed. diff --git a/twilight-model/src/gateway/payload/incoming/mod.rs b/twilight-model/src/gateway/payload/incoming/mod.rs index a89f3683421..06ee2ea41dc 100644 --- a/twilight-model/src/gateway/payload/incoming/mod.rs +++ b/twilight-model/src/gateway/payload/incoming/mod.rs @@ -71,6 +71,7 @@ mod thread_update; mod typing_start; mod unavailable_guild; mod user_update; +mod voice_channel_effect_send; mod voice_server_update; mod voice_state_update; mod webhooks_update; @@ -79,33 +80,64 @@ pub use self::{ auto_moderation_action_execution::AutoModerationActionExecution, auto_moderation_rule_create::AutoModerationRuleCreate, auto_moderation_rule_delete::AutoModerationRuleDelete, - auto_moderation_rule_update::AutoModerationRuleUpdate, ban_add::BanAdd, ban_remove::BanRemove, - channel_create::ChannelCreate, channel_delete::ChannelDelete, - channel_pins_update::ChannelPinsUpdate, channel_update::ChannelUpdate, + auto_moderation_rule_update::AutoModerationRuleUpdate, + ban_add::BanAdd, + ban_remove::BanRemove, + channel_create::ChannelCreate, + channel_delete::ChannelDelete, + channel_pins_update::ChannelPinsUpdate, + channel_update::ChannelUpdate, command_permissions_update::CommandPermissionsUpdate, - guild_audit_log_entry_create::GuildAuditLogEntryCreate, guild_create::GuildCreate, - guild_delete::GuildDelete, guild_emojis_update::GuildEmojisUpdate, + guild_audit_log_entry_create::GuildAuditLogEntryCreate, + guild_create::GuildCreate, + guild_delete::GuildDelete, + guild_emojis_update::GuildEmojisUpdate, guild_integrations_update::GuildIntegrationsUpdate, guild_scheduled_event_create::GuildScheduledEventCreate, guild_scheduled_event_delete::GuildScheduledEventDelete, guild_scheduled_event_update::GuildScheduledEventUpdate, guild_scheduled_event_user_add::GuildScheduledEventUserAdd, guild_scheduled_event_user_remove::GuildScheduledEventUserRemove, - guild_stickers_update::GuildStickersUpdate, guild_update::GuildUpdate, hello::Hello, - integration_create::IntegrationCreate, integration_delete::IntegrationDelete, - integration_update::IntegrationUpdate, interaction_create::InteractionCreate, - invite_create::InviteCreate, invite_delete::InviteDelete, member_add::MemberAdd, - member_chunk::MemberChunk, member_remove::MemberRemove, member_update::MemberUpdate, - message_create::MessageCreate, message_delete::MessageDelete, - message_delete_bulk::MessageDeleteBulk, message_update::MessageUpdate, - presence_update::PresenceUpdate, reaction_add::ReactionAdd, reaction_remove::ReactionRemove, - reaction_remove_all::ReactionRemoveAll, reaction_remove_emoji::ReactionRemoveEmoji, - ready::Ready, role_create::RoleCreate, role_delete::RoleDelete, role_update::RoleUpdate, - stage_instance_create::StageInstanceCreate, stage_instance_delete::StageInstanceDelete, - stage_instance_update::StageInstanceUpdate, thread_create::ThreadCreate, - thread_delete::ThreadDelete, thread_list_sync::ThreadListSync, - thread_member_update::ThreadMemberUpdate, thread_members_update::ThreadMembersUpdate, - thread_update::ThreadUpdate, typing_start::TypingStart, unavailable_guild::UnavailableGuild, - user_update::UserUpdate, voice_server_update::VoiceServerUpdate, - voice_state_update::VoiceStateUpdate, webhooks_update::WebhooksUpdate, + guild_stickers_update::GuildStickersUpdate, + guild_update::GuildUpdate, + hello::Hello, + integration_create::IntegrationCreate, + integration_delete::IntegrationDelete, + integration_update::IntegrationUpdate, + interaction_create::InteractionCreate, + invite_create::InviteCreate, + invite_delete::InviteDelete, + member_add::MemberAdd, + member_chunk::MemberChunk, + member_remove::MemberRemove, + member_update::MemberUpdate, + message_create::MessageCreate, + message_delete::MessageDelete, + message_delete_bulk::MessageDeleteBulk, + message_update::MessageUpdate, + presence_update::PresenceUpdate, + reaction_add::ReactionAdd, + reaction_remove::ReactionRemove, + reaction_remove_all::ReactionRemoveAll, + reaction_remove_emoji::ReactionRemoveEmoji, + ready::Ready, + role_create::RoleCreate, + role_delete::RoleDelete, + role_update::RoleUpdate, + stage_instance_create::StageInstanceCreate, + stage_instance_delete::StageInstanceDelete, + stage_instance_update::StageInstanceUpdate, + thread_create::ThreadCreate, + thread_delete::ThreadDelete, + thread_list_sync::ThreadListSync, + thread_member_update::ThreadMemberUpdate, + thread_members_update::ThreadMembersUpdate, + thread_update::ThreadUpdate, + typing_start::TypingStart, + unavailable_guild::UnavailableGuild, + user_update::UserUpdate, + voice_channel_effect_send::{VoiceChannelEffectAnimationType, VoiceChannelEffectSend}, + voice_server_update::VoiceServerUpdate, + voice_state_update::VoiceStateUpdate, + webhooks_update::WebhooksUpdate, }; diff --git a/twilight-model/src/gateway/payload/incoming/voice_channel_effect_send.rs b/twilight-model/src/gateway/payload/incoming/voice_channel_effect_send.rs new file mode 100644 index 00000000000..27c14a8312f --- /dev/null +++ b/twilight-model/src/gateway/payload/incoming/voice_channel_effect_send.rs @@ -0,0 +1,114 @@ +use crate::{ + guild::Emoji, + id::{ + marker::{ChannelMarker, GuildMarker, UserMarker}, + Id, + }, +}; +use serde::{Deserialize, Serialize}; + +/// Sent when someone sends an effect, such as an emoji reaction, in a voice channel the current user is connected to. +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct VoiceChannelEffectSend { + /// The ID of the emoji animation, for emoji reaction effects + #[serde(skip_serializing_if = "Option::is_none")] + pub animation_id: Option, + /// The type of emoji animation, for emoji reaction effects. + #[serde(skip_serializing_if = "Option::is_none")] + pub animation_type: Option, + /// ID of the channel the effect was sent in. + pub channel_id: Id, + /// The emoji sent, for emoji reaction effects. + #[serde(skip_serializing_if = "Option::is_none")] + pub emoji: Option, + /// ID of the guild the effect was sent in. + pub guild_id: Id, + /// ID of the user who sent the effect + pub user_id: Id, +} + +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub enum VoiceChannelEffectAnimationType { + /// A fun animation, sent by a Nitro subscriber. + Premium, + /// The standard animation. + Basic, +} + +#[cfg(test)] +mod tests { + use super::{VoiceChannelEffectAnimationType, VoiceChannelEffectSend}; + use crate::{guild::Emoji, id::Id}; + use serde_test::Token; + + #[test] + fn voice_channel_effect_send() { + let value = VoiceChannelEffectSend { + animation_id: Some(42), + animation_type: Some(VoiceChannelEffectAnimationType::Premium), + channel_id: Id::new(1), + emoji: Some(Emoji { + animated: true, + available: true, + id: Id::new(6), + managed: true, + name: "test".to_string(), + require_colons: true, + roles: vec![], + user: None, + }), + guild_id: Id::new(42), + user_id: Id::new(24), + }; + + serde_test::assert_tokens( + &value, + &[ + Token::Struct { + name: "VoiceChannelEffectSend", + len: 6, + }, + Token::Str("animation_id"), + Token::Some, + Token::U64(42), + Token::Str("animation_type"), + Token::Some, + Token::Enum { + name: "VoiceChannelEffectAnimationType", + }, + Token::Str("Premium"), + Token::Unit, + Token::Str("channel_id"), + Token::NewtypeStruct { name: "Id" }, + Token::Str("1"), + Token::Str("emoji"), + Token::Some, + Token::Struct { + name: "Emoji", + len: 6, + }, + Token::Str("animated"), + Token::Bool(true), + Token::Str("available"), + Token::Bool(true), + Token::Str("id"), + Token::NewtypeStruct { name: "Id" }, + Token::Str("6"), + Token::Str("managed"), + Token::Bool(true), + Token::Str("name"), + Token::Str("test"), + Token::Str("require_colons"), + Token::Bool(true), + Token::StructEnd, + Token::Str("guild_id"), + Token::NewtypeStruct { name: "Id" }, + Token::Str("42"), + Token::Str("user_id"), + Token::NewtypeStruct { name: "Id" }, + Token::Str("24"), + Token::StructEnd, + ], + ) + } +}