bevy_discord/bot/
mod.rs

1// Not Accessible Publicly
2
3//! Discord bot integration for Bevy applications.
4//!
5//! This module provides a plugin system for integrating a Discord bot into your Bevy application,
6//! handling Discord events, and managing the bot's state. It wraps Serenity's client functionality
7//! while providing a Bevy-friendly interface.
8//!
9//! # Features
10//!
11//! - Complete Discord event integration with Bevy's event system
12//! - Bot configuration management (status, activity, intents)
13//! - Asynchronous event handling
14//!
15//! # Example
16//!
17//! ```no_run
18//! use bevy::prelude::*;
19//! use bevy_discord::bot::{DiscordBotPlugin, DiscordBotConfig};
20//! use bevy_discord::serenity::all::GatewayIntents;
21//!
22//! let config = DiscordBotConfig::default()
23//!     .token("your-bot-token".to_string())
24//!     .gateway_intents(GatewayIntents::non_privileged());
25//!
26//! App::new()
27//!     .add_plugins(DiscordBotPlugin::new(config))
28//!     .run();
29//! ```
30//!
31//! # Note
32//!
33//! For HTTP interactions with Discord's API, see the [`http`](crate::http) module.
34
35use bevy_app::{App, Plugin, Startup, Update};
36use bevy_ecs::prelude::*;
37use serenity::all::*;
38
39use crate::messages::{MessageCollectionBot, bot::*, send_events_bot};
40use event_handlers::*;
41
42use crate::DiscordSystems;
43use crate::bot::handle::Handle;
44use crate::channel::ChannelRes;
45use crate::runtime::tokio_runtime;
46
47pub(crate) mod event_handlers;
48mod handle;
49
50/// A plugin that integrates Discord bot functionality into a Bevy application.
51///
52/// # Functionality
53///
54/// This plugin handles:
55/// - Discord client initialization and lifecycle management
56/// - Event system integration between Discord and Bevy
57/// - Bot presence and status management
58/// - Gateway connection and communication
59///
60/// # Usage
61///
62/// ```no_run
63/// use bevy::prelude::*;
64/// use bevy_discord::bot::{DiscordBotPlugin, DiscordBotConfig};
65/// use bevy_discord::serenity::all::{GatewayIntents, ActivityData, ActivityType};
66///
67/// // Configure your bot
68/// let config = DiscordBotConfig::default()
69///     .token("your-bot-token".to_string())
70///     .gateway_intents(GatewayIntents::non_privileged())
71///     .activity(ActivityData::playing("with Bevy!"));
72///
73/// App::new()
74///     .add_plugins(DiscordBotPlugin::new(config))
75///     .run();
76/// ```
77///
78/// # Features
79///
80/// - Automatically makes available [DiscordHttpResource](crate::res::DiscordHttpResource)
81/// - Registers all Discord events as Bevy events
82/// - Manages bot configuration and presence
83/// - Provides asynchronous event handling
84///
85/// # Note
86///
87/// This plugin requires a valid Discord bot token and appropriate gateway intents
88/// to function correctly. Make sure to configure the necessary intents based on
89/// your bot's requirements.
90#[derive(Debug, Clone)]
91pub struct DiscordBotPlugin(crate::config::DiscordBotConfig);
92
93impl DiscordBotPlugin {
94    /// Creates a new instance of `DiscordBotPlugin` with the specified configuration.
95    ///
96    /// # Arguments
97    ///
98    /// * `configuration` - Bot configuration including token, intents, and presence settings
99    pub fn new(configuration: crate::config::DiscordBotConfig) -> Self {
100        Self(configuration)
101    }
102}
103
104impl Plugin for DiscordBotPlugin {
105    fn build(&self, app: &mut App) {
106        let (tx, rx) = flume::unbounded::<MessageCollectionBot>();
107        let channel_res = ChannelRes { tx, rx };
108        app.insert_resource(channel_res);
109
110        #[cfg(feature = "bot_cache")]
111        app.add_message::<CacheReadMessage>()
112            .add_message::<ShardsReadyMessage>();
113
114        app.insert_resource(self.0.clone())
115            .add_message::<BotReadyMessage>()
116            .add_message::<CommandPermissionsUpdateMessage>()
117            .add_message::<AutoModerationRuleCreateMessage>()
118            .add_message::<AutoModerationRuleUpdateMessage>()
119            .add_message::<AutoModerationRuleDeleteMessage>()
120            .add_message::<AutoModerationActionExecutionMessage>()
121            .add_message::<ChannelCreateMessage>()
122            .add_message::<CategoryCreateMessage>()
123            .add_message::<CategoryDeleteMessage>()
124            .add_message::<ChannelDeleteMessage>()
125            .add_message::<ChannelPinUpdateMessage>()
126            .add_message::<ChannelUpdateMessage>()
127            .add_message::<GuildAuditLogEntryCreateMessage>()
128            .add_message::<GuildBanAdditionMessage>()
129            .add_message::<GuildBanRemovalMessage>()
130            .add_message::<GuildCreateMessage>()
131            .add_message::<GuildDeleteMessage>()
132            .add_message::<GuildEmojisUpdateMessage>()
133            .add_message::<GuildIntegrationsUpdateMessage>()
134            .add_message::<GuildMemberAdditionMessage>()
135            .add_message::<GuildMemberRemovalMessage>()
136            .add_message::<GuildMemberUpdateMessage>()
137            .add_message::<GuildMembersChunkMessage>()
138            .add_message::<GuildRoleCreateMessage>()
139            .add_message::<GuildRoleDeleteMessage>()
140            .add_message::<GuildRoleUpdateMessage>()
141            .add_message::<GuildStickersUpdateMessage>()
142            .add_message::<GuildUpdateMessage>()
143            .add_message::<InviteCreateMessage>()
144            .add_message::<InviteDeleteMessage>()
145            .add_message::<DiscordMessage>()
146            .add_message::<DiscordMessageDeleteMessage>()
147            .add_message::<DiscordMessageDeleteBulkMessage>()
148            .add_message::<DiscordMessageUpdateMessage>()
149            .add_message::<ReactionAddMessage>()
150            .add_message::<ReactionRemoveMessage>()
151            .add_message::<ReactionRemoveAllMessage>()
152            .add_message::<ReactionRemoveEmojiMessage>()
153            .add_message::<PresenceUpdateMessage>()
154            .add_message::<ResumeMessage>()
155            .add_message::<ShardStageUpdateMessage>()
156            .add_message::<TypingStartMessage>()
157            .add_message::<UserUpdateMessage>()
158            .add_message::<VoiceServerUpdateMessage>()
159            .add_message::<VoiceStateUpdateMessage>()
160            .add_message::<VoiceChannelStatusUpdateMessage>()
161            .add_message::<WebhookUpdateMessage>()
162            .add_message::<InteractionCreateMessage>()
163            .add_message::<IntegrationCreateMessage>()
164            .add_message::<IntegrationUpdateMessage>()
165            .add_message::<StageInstanceCreateMessage>()
166            .add_message::<StageInstanceUpdateMessage>()
167            .add_message::<StageInstanceDeleteMessage>()
168            .add_message::<ThreadCreateMessage>()
169            .add_message::<ThreadUpdateMessage>()
170            .add_message::<ThreadDeleteMessage>()
171            .add_message::<ThreadListSyncMessage>()
172            .add_message::<ThreadMemberUpdateMessage>()
173            .add_message::<ThreadMembersUpdateMessage>()
174            .add_message::<GuildScheduledEventCreateMessage>()
175            .add_message::<GuildScheduledEventUpdateMessage>()
176            .add_message::<GuildScheduledEventDeleteMessage>()
177            .add_message::<GuildScheduledEventUserAddMessage>()
178            .add_message::<GuildScheduledEventUserRemoveMessage>()
179            .add_message::<EntitlementCreateMessage>()
180            .add_message::<EntitlementUpdateMessage>()
181            .add_message::<EntitlementDeleteMessage>()
182            .add_message::<PollVoteAddMessage>()
183            .add_message::<PollVoteRemoveMessage>()
184            .add_message::<RateLimitMessage>()
185            .add_systems(Startup, setup_bot.in_set(DiscordSystems))
186            .add_systems(
187                Update,
188                (handle_b_ready_message, send_events_bot)
189                    .chain()
190                    .in_set(DiscordSystems),
191            );
192    }
193}
194
195fn setup_bot(
196    discord_bot_config: Res<crate::config::DiscordBotConfig>,
197    channel_res: Res<ChannelRes<MessageCollectionBot>>,
198) {
199    let tx = channel_res.tx.clone();
200
201    let mut client_builder = Client::builder(
202        &discord_bot_config.token,
203        discord_bot_config.gateway_intents,
204    )
205    .event_handler(Handle { tx });
206
207    let discord_bot_res_clone = discord_bot_config.clone();
208
209    if let Some(status) = discord_bot_res_clone.status {
210        client_builder = client_builder.status(status);
211    }
212
213    if let Some(activity) = discord_bot_res_clone.activity {
214        client_builder = client_builder.activity(activity);
215    }
216
217    let discord_bot_config_clone = discord_bot_config.clone();
218
219    tokio_runtime().spawn(async move {
220        let mut client = client_builder
221            .await
222            .expect("Unable to build discord Client");
223
224        if discord_bot_config_clone.shards == 0 {
225            client
226                .start()
227                .await
228                .expect("Unable to run the discord Client");
229        } else {
230            client
231                .start_shards(discord_bot_config_clone.shards)
232                .await
233                .expect("Unable to run the discord Client with multiple shards.")
234        }
235    });
236}