bevy_drpc/
lib.rs

1//! A simple unfinished bevy plugin for Discord RPC
2
3pub use discord_presence;
4
5pub mod config;
6
7/// The main library crate containing bevy-specific structs/impls/functions
8pub mod plugin {
9    use std::ops::DerefMut;
10
11    use bevy::{app::{Plugin, Startup, Update}, log::{debug, error, warn}, prelude::{Deref, Event, EventReader, ResMut, Resource}};
12    use discord_presence::{models::Activity, Client as DiscordClient, DiscordError};
13
14    use crate::config::RPCPlugin;
15
16    #[derive(Resource, Deref)]
17    struct Client(DiscordClient);
18
19    /// Event which updates the current Discord activity
20    #[derive(Event, Deref)]
21    pub struct ActivityUpdate(pub Activity);
22
23    /// Generate a default ActivityUpdate instance with an empty Activity struct
24    impl Default for ActivityUpdate {
25        fn default() -> Self {
26            Self(Activity::default())
27        }
28    }
29
30    impl DerefMut for Client {
31        fn deref_mut(&mut self) -> &mut Self::Target {
32            &mut self.0
33        }
34    }
35
36    impl Client {
37        pub fn new(client_id: u64) -> Self {
38            let rpc = DiscordClient::new(client_id);
39            rpc.on_error(|e| error!("DiscordClient got an error: {e:#?}")).persist();
40
41            Client(rpc)
42        }
43    }
44
45    impl Plugin for RPCPlugin {
46        fn build(&self, app: &mut bevy::prelude::App) {
47            let cc = &self.config;
48
49            app.add_systems(Startup, startup_client);
50            app.add_systems(Update, update_activity);
51            
52            app.insert_resource(Client::new(cc.app_id));
53            app.add_event::<ActivityUpdate>();
54        }
55        
56        fn name(&self) -> &str {
57            "Discord Presence"
58        }
59    }
60
61    fn startup_client(mut client: ResMut<Client>) {
62        client.0.start();
63    }
64
65    fn update_activity(mut client: ResMut<Client>, mut activity_update: EventReader<ActivityUpdate>) {
66        let event = match activity_update.read().next() {
67            Some(v) => v,
68            None => return,
69        };
70    
71        let activity = &event.0; // Clone activity if needed for async use
72    
73        __update_activity(&mut client, activity)
74    }
75
76    fn __update_activity(client: &mut DiscordClient, activity: &Activity) {
77        let update_err = match client.set_activity(|_| { activity.clone() }) {
78            Ok(v) => {
79                debug!("Activity updated: {v:#?}");
80                return;
81            },
82            Err(e) => e
83        };
84
85        match update_err {
86            DiscordError::IoError(error) => error!("Discord RPC error occurred: {error}"),
87            DiscordError::SendMessage(error) => error!("An MPSC send error occurred: {error}"),
88            DiscordError::CloseError(error) => error!("An MPSC send error occurred: {error}"),
89            DiscordError::ReceiveError(error) => error!("An MPSC receive error occurred: {error}"),
90            DiscordError::MPSCReceiveError(error) => error!("An MPSC receive error occurred: {error}"),
91            DiscordError::MPSCTimeout(error) => error!("The MPSC channel timed out: {error}"),
92            DiscordError::TimeoutError(error) => error!("The MPSC channel timed out: {error}"),
93            DiscordError::JsonError(error) => error!("A JSON serialization error occurred: {error}"),
94            DiscordError::ThreadError => error!("A discord_presence thread ran into an unexpected error."),
95            DiscordError::NoneError(_) => error!("The library discord_presence unwrapped an Option<T> on a None value"),
96            DiscordError::Conversion => error!("An unspecified conversion error occurred"),
97            DiscordError::SubscriptionFailed => error!("An event subscription error occurred"),
98            DiscordError::ConnectionClosed => error!("The connection was unexpectedly closed"),
99            DiscordError::NotStarted => error!("The client has not started yet!"),
100            DiscordError::EventLoopError => error!("The MPSC send & receive loop ran into an error"),
101            DiscordError::NoChangesMade => warn!("No changes were made to the event handle"),
102            DiscordError::ThreadInUse => error!("The RPC thread is in use"),
103        }
104    }
105}