- added experimental discord rpc support
This commit is contained in:
Observer KRypt0n_ 2023-03-02 22:26:32 +02:00
parent f1f8eb6a2c
commit 420326a8a0
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
7 changed files with 229 additions and 8 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "anime-launcher-sdk"
version = "0.1.1"
version = "0.2.0"
authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"]
license = "GPL-3.0"
readme = "README.md"
@ -20,6 +20,7 @@ enum-ordinalize = { version = "3.1", optional = true }
wincompatlib = { version = "0.2", optional = true }
lazy_static = { version = "1.4", optional = true }
md-5 = { version = "0.10", features = ["asm"], optional = true }
discord-rich-presence = { version = "0.2.3", optional = true }
[features]
states = []
@ -27,6 +28,7 @@ config = ["dep:serde", "dep:serde_json", "dep:enum-ordinalize"]
components = ["dep:wincompatlib", "dep:lazy_static"]
game = ["components", "config"]
fps-unlocker = ["dep:md-5"]
discord-rpc = ["dep:discord-rich-presence"]
default = ["all"]
all = ["states", "config", "components", "game", "fps-unlocker"]
all = ["states", "config", "components", "game", "fps-unlocker", "discord-rpc"]

View file

@ -3,16 +3,22 @@ use serde_json::Value as JsonValue;
pub mod fsr;
pub mod hud;
pub mod fps_unlocker;
pub mod gamescope;
#[cfg(feature = "fps-unlocker")]
pub mod fps_unlocker;
pub mod prelude {
pub use super::gamescope::prelude::*;
#[cfg(feature = "fps-unlocker")]
pub use super::fps_unlocker::prelude::*;
pub use super::Enhancements;
pub use super::fsr::Fsr;
pub use super::hud::HUD;
#[cfg(feature = "fps-unlocker")]
pub use super::fps_unlocker::FpsUnlocker;
}
@ -23,7 +29,10 @@ pub struct Enhancements {
pub fsr: Fsr,
pub gamemode: bool,
pub hud: HUD,
#[cfg(feature = "fps-unlocker")]
pub fps_unlocker: FpsUnlocker,
pub gamescope: Gamescope
}
@ -47,6 +56,7 @@ impl From<&JsonValue> for Enhancements {
None => default.hud
},
#[cfg(feature = "fps-unlocker")]
fps_unlocker: match value.get("fps_unlocker") {
Some(value) => FpsUnlocker::from(value),
None => default.fps_unlocker

View file

@ -0,0 +1,57 @@
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DiscordRpc {
pub app_id: u64,
pub enabled: bool,
pub title: String,
pub subtitle: String,
pub icon: String
}
impl Default for DiscordRpc {
fn default() -> Self {
Self {
app_id: 901534333360304168,
enabled: false,
title: String::from("Researching the world"),
subtitle: String::from("of Teyvat"),
icon: String::from("launcher")
}
}
}
impl From<&JsonValue> for DiscordRpc {
fn from(value: &JsonValue) -> Self {
let default = Self::default();
Self {
app_id: match value.get("app_id") {
Some(value) => value.as_u64().unwrap_or(default.app_id),
None => default.app_id
},
enabled: match value.get("enabled") {
Some(value) => value.as_bool().unwrap_or(default.enabled),
None => default.enabled
},
title: match value.get("title") {
Some(value) => value.as_str().unwrap_or(&default.title).to_string(),
None => default.title
},
subtitle: match value.get("subtitle") {
Some(value) => value.as_str().unwrap_or(&default.subtitle).to_string(),
None => default.subtitle
},
icon: match value.get("icon") {
Some(value) => value.as_str().unwrap_or(&default.icon).to_string(),
None => default.icon
}
}
}
}

View file

@ -11,9 +11,15 @@ use crate::consts::launcher_dir;
pub mod repairer;
#[cfg(feature = "discord-rpc")]
pub mod discord_rpc;
pub mod prelude {
pub use super::Launcher;
pub use super::repairer::Repairer;
#[cfg(feature = "discord-rpc")]
pub use super::discord_rpc::DiscordRpc;
}
use prelude::*;
@ -33,7 +39,7 @@ impl Default for GameEdition {
})
});
if locale.len() > 4 && &locale[..5].to_lowercase() == "zh_cn" {
if locale.len() > 4 && &locale[..5].to_ascii_lowercase() == "zh_cn" {
Self::China
} else {
Self::Global
@ -80,7 +86,10 @@ pub struct Launcher {
pub speed_limit: u64,
pub repairer: Repairer,
pub edition: GameEdition,
pub style: LauncherStyle
pub style: LauncherStyle,
#[cfg(feature = "discord-rpc")]
pub discord_rpc: DiscordRpc
}
impl Default for Launcher {
@ -91,7 +100,10 @@ impl Default for Launcher {
speed_limit: 0,
repairer: Repairer::default(),
edition: GameEdition::default(),
style: LauncherStyle::default()
style: LauncherStyle::default(),
#[cfg(feature = "discord-rpc")]
discord_rpc: DiscordRpc::default()
}
}
}
@ -138,6 +150,12 @@ impl From<&JsonValue> for Launcher {
style: match value.get("style") {
Some(value) => serde_json::from_value(value.clone()).unwrap_or(default.style),
None => default.style
},
#[cfg(feature = "discord-rpc")]
discord_rpc: match value.get("discord_rpc") {
Some(value) => DiscordRpc::from(value),
None => default.discord_rpc
}
}
}

108
src/discord_rpc.rs Normal file
View file

@ -0,0 +1,108 @@
use std::thread::JoinHandle;
use std::sync::mpsc::{self, Sender, SendError};
use discord_rich_presence::{
activity::*,
DiscordIpc,
DiscordIpcClient
};
use super::config::prelude::DiscordRpc as DiscordRpcConfig;
#[derive(Debug, Clone)]
pub enum RpcUpdates {
/// Establish RPC connection
Connect,
/// Terminate RPC connection. Panics if not connected
Disconnect,
/// Update RPC activity
UpdateActivity {
title: String,
subtitle: String,
icon: String
},
/// Clear RPC activity
ClearActivity
}
pub struct DiscordRpc {
_thread: JoinHandle<()>,
sender: Sender<RpcUpdates>
}
impl DiscordRpc {
pub fn new(mut config: DiscordRpcConfig) -> Self {
let (sender, receiver) = mpsc::channel();
Self {
_thread: std::thread::spawn(move || {
let mut client = DiscordIpcClient::new(&config.app_id.to_string())
.expect("Failed to register discord ipc client");
let mut connected = false;
while let Ok(update) = receiver.recv() {
match update {
RpcUpdates::Connect => {
if !connected {
connected = true;
client.connect().expect("Failed to connect to discord");
client.set_activity(Self::get_activity(&config))
.expect("Failed to update discord rpc activity");
}
}
RpcUpdates::Disconnect => {
if connected {
connected = false;
client.close().expect("Failed to disconnect from discord");
}
}
RpcUpdates::UpdateActivity { title, subtitle, icon } => {
config.title = title;
config.subtitle = subtitle;
config.icon = icon;
if connected {
client.set_activity(Self::get_activity(&config))
.expect("Failed to update discord rpc activity");
}
}
RpcUpdates::ClearActivity => {
if connected {
client.clear_activity().expect("Failed to clear discord rpc activity");
}
}
}
}
}),
sender
}
}
pub fn get_activity(config: &DiscordRpcConfig) -> Activity {
Activity::new()
.details(&config.title)
.state(&config.subtitle)
.assets(Assets::new().large_image(&config.icon))
}
pub fn update(&self, update: RpcUpdates) -> Result<(), SendError<RpcUpdates>> {
self.sender.send(update)
}
}
impl Drop for DiscordRpc {
#[allow(unused_must_use)]
fn drop(&mut self) {
self.update(RpcUpdates::Disconnect);
}
}

View file

@ -1,4 +1,4 @@
use std::process::Command;
use std::process::{Command, Stdio};
use anime_game_core::genshin::telemetry;
@ -8,6 +8,9 @@ use super::config;
#[cfg(feature = "fps-unlocker")]
use super::fps_unlocker::FpsUnlocker;
#[cfg(feature = "discord-rpc")]
use super::discord_rpc::*;
/// Try to run the game
///
/// If `debug = true`, then the game will be run in the new terminal window
@ -63,7 +66,7 @@ pub fn run() -> anyhow::Result<()> {
};
// Generate FPS unlocker config file
if let Err(err) = unlocker.update_config(config.game.enhancements.fps_unlocker.config.clone()) {
if let Err(err) = unlocker.update_config(config.game.enhancements.fps_unlocker.config) {
return Err(anyhow::anyhow!("Failed to update FPS unlocker config: {err}"));
}
@ -150,5 +153,25 @@ pub fn run() -> anyhow::Result<()> {
command.current_dir(config.game.path).spawn()?;
#[cfg(feature = "discord-rpc")]
if config.launcher.discord_rpc.enabled {
let rpc = DiscordRpc::new(config.launcher.discord_rpc);
rpc.update(RpcUpdates::Connect)?;
#[allow(unused_must_use)]
std::thread::spawn(move || {
while let Ok(output) = Command::new("ps").arg("-A").stdout(Stdio::piped()).output() {
let output = String::from_utf8_lossy(&output.stdout);
if !output.contains("GenshinImpact.e") && !output.contains("unlocker.exe") {
break;
}
}
rpc.update(RpcUpdates::Disconnect);
});
}
Ok(())
}

View file

@ -20,6 +20,9 @@ pub mod game;
#[cfg(feature = "fps-unlocker")]
pub mod fps_unlocker;
#[cfg(feature = "discord-rpc")]
pub mod discord_rpc;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
/// Check if specified binary is available