Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow DiscordRPC to be reloaded #27

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
7 changes: 5 additions & 2 deletions src/discord.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![deny(non_snake_case)]

use std::num::NonZeroU32;
use std::{num::NonZeroU32, sync::atomic::Ordering};

use discord_sdk::{
activity::{events::ActivityEvent, ActivityBuilder, Assets, JoinRequestReply, PartyPrivacy},
Expand Down Expand Up @@ -46,7 +46,10 @@ pub async fn async_main() {

let mut events = client.wheel.activity().0;

loop {
while PLUGIN
.get()
.is_some_and(|plugin| plugin.is_active.load(Ordering::Acquire))
{
let data = activity.lock().clone();

if let Some(img) = &data.large_image {
Expand Down
32 changes: 29 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#![allow(non_snake_case)]

use std::sync::atomic::{AtomicBool, Ordering};

use discord_sdk::activity::Secrets;
use parking_lot::Mutex;
use rrplug::prelude::*;
use rrplug::{bindings::plugin_abi::PluginColor, interfaces::manager::register_interface};
use tokio::runtime::Runtime;
use tokio::task::JoinHandle;

use crate::{
discord::async_main,
Expand Down Expand Up @@ -39,6 +42,8 @@ pub struct ActivityData {
pub struct DiscordRpcPlugin {
pub activity: Mutex<ActivityData>,
pub presence_data: Mutex<(GameStateStruct, UIPresenceStruct)>,
pub runtime: Mutex<Option<(Runtime, JoinHandle<()>)>>,
pub is_active: AtomicBool,
}

#[deny(non_snake_case)]
Expand Down Expand Up @@ -66,16 +71,22 @@ impl Plugin for DiscordRpcPlugin {
..Default::default()
});

std::thread::spawn(|| match Runtime::new() {
Ok(rt) => rt.block_on(async_main()),
let rt = match Runtime::new() {
Ok(rt) => {
let handle = rt.spawn(async_main());
Some((rt, handle))
}
Err(err) => {
log::error!("failed to create a runtime; {:?}", err);
None
}
});
};

Self {
activity,
presence_data: Mutex::new((GameStateStruct::default(), UIPresenceStruct::default())),
runtime: Mutex::new(rt),
is_active: AtomicBool::new(true),
}
}

Expand All @@ -87,6 +98,21 @@ impl Plugin for DiscordRpcPlugin {
_ => {}
}
}

fn on_reload_request(&self) -> reloading::ReloadResponse {
let (runtime, handle) = self
.runtime
.lock()
.take()
.expect("runtime should exist when unloading the plugin");
self.is_active.store(false, Ordering::Release);
runtime.block_on(async { _ = handle.await });
runtime.shutdown_background();

log::info!("reloading request for DiscordRpc");
// SAFETY: this plugin doesn't have anything that gets called or referenced from the game (usally) so it's safe
unsafe { reloading::ReloadResponse::allow_reload() }
}
}

entry!(DiscordRpcPlugin);