From 3e7f38f2103f50469b38df5c297e4544224f097f Mon Sep 17 00:00:00 2001 From: Observer KRypt0n_ Date: Fri, 14 Apr 2023 21:13:48 +0200 Subject: [PATCH] feat: added `game` and `discord_rpc` to honkers feature --- src/config/schema_blanks/fsr.rs | 6 +- src/discord_rpc.rs | 25 +++-- src/honkai/config/mod.rs | 2 + .../config/schema/launcher/discord_rpc.rs | 15 +++ src/honkai/config/schema/launcher/mod.rs | 22 +++++ src/honkai/config/schema/mod.rs | 26 ++++++ src/{ => honkai}/game.rs | 92 ++++--------------- src/honkai/mod.rs | 3 + src/lib.rs | 5 +- 9 files changed, 104 insertions(+), 92 deletions(-) rename src/{ => honkai}/game.rs (58%) diff --git a/src/config/schema_blanks/fsr.rs b/src/config/schema_blanks/fsr.rs index a704bfb..8018687 100644 --- a/src/config/schema_blanks/fsr.rs +++ b/src/config/schema_blanks/fsr.rs @@ -39,11 +39,11 @@ impl From<&JsonValue> for Fsr { impl Fsr { /// Get environment variables corresponding to used amd fsr options - pub fn get_env_vars(&self) -> HashMap<&str, u64> { + pub fn get_env_vars(&self) -> HashMap<&str, String> { if self.enabled { HashMap::from([ - ("WINE_FULLSCREEN_FSR", 1), - ("WINE_FULLSCREEN_FSR_STRENGTH", self.strength) + ("WINE_FULLSCREEN_FSR", String::from("1")), + ("WINE_FULLSCREEN_FSR_STRENGTH", self.strength.to_string()) ]) } diff --git a/src/discord_rpc.rs b/src/discord_rpc.rs index d278a05..0d7416c 100644 --- a/src/discord_rpc.rs +++ b/src/discord_rpc.rs @@ -7,7 +7,14 @@ use discord_rich_presence::{ DiscordIpcClient }; -use super::config::prelude::DiscordRpc as DiscordRpcConfig; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct DiscordRpcParams { + pub app_id: u64, + pub enabled: bool, + pub title: String, + pub subtitle: String, + pub icon: String +} #[derive(Debug, Clone)] pub enum RpcUpdates { @@ -34,12 +41,12 @@ pub struct DiscordRpc { } impl DiscordRpc { - pub fn new(mut config: DiscordRpcConfig) -> Self { + pub fn new(mut params: DiscordRpcParams) -> Self { let (sender, receiver) = mpsc::channel(); Self { _thread: std::thread::spawn(move || { - let mut client = DiscordIpcClient::new(&config.app_id.to_string()) + let mut client = DiscordIpcClient::new(¶ms.app_id.to_string()) .expect("Failed to register discord ipc client"); let mut connected = false; @@ -52,7 +59,7 @@ impl DiscordRpc { client.connect().expect("Failed to connect to discord"); - client.set_activity(Self::get_activity(&config)) + client.set_activity(Self::get_activity(¶ms)) .expect("Failed to update discord rpc activity"); } } @@ -66,12 +73,12 @@ impl DiscordRpc { } RpcUpdates::UpdateActivity { title, subtitle, icon } => { - config.title = title; - config.subtitle = subtitle; - config.icon = icon; + params.title = title; + params.subtitle = subtitle; + params.icon = icon; if connected { - client.set_activity(Self::get_activity(&config)) + client.set_activity(Self::get_activity(¶ms)) .expect("Failed to update discord rpc activity"); } } @@ -88,7 +95,7 @@ impl DiscordRpc { } } - pub fn get_activity(config: &DiscordRpcConfig) -> Activity { + pub fn get_activity(config: &DiscordRpcParams) -> Activity { Activity::new() .details(&config.title) .state(&config.subtitle) diff --git a/src/honkai/config/mod.rs b/src/honkai/config/mod.rs index 94be9a6..210f6b4 100644 --- a/src/honkai/config/mod.rs +++ b/src/honkai/config/mod.rs @@ -2,6 +2,8 @@ use std::path::PathBuf; pub mod schema; +pub use schema::Schema; + use crate::config::Config as ConfigTrait; use crate::honkai::consts::config_file; diff --git a/src/honkai/config/schema/launcher/discord_rpc.rs b/src/honkai/config/schema/launcher/discord_rpc.rs index b659305..7e787e4 100644 --- a/src/honkai/config/schema/launcher/discord_rpc.rs +++ b/src/honkai/config/schema/launcher/discord_rpc.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; +use crate::discord_rpc::DiscordRpcParams; + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DiscordRpc { pub app_id: u64, @@ -10,6 +12,19 @@ pub struct DiscordRpc { pub icon: String } +impl From for DiscordRpcParams { + #[inline] + fn from(config: DiscordRpc) -> Self { + Self { + app_id: config.app_id, + enabled: config.enabled, + title: config.title, + subtitle: config.subtitle, + icon: config.icon + } + } +} + // TODO: add honkers-specific discord rpc impl Default for DiscordRpc { diff --git a/src/honkai/config/schema/launcher/mod.rs b/src/honkai/config/schema/launcher/mod.rs index e557744..2c8e881 100644 --- a/src/honkai/config/schema/launcher/mod.rs +++ b/src/honkai/config/schema/launcher/mod.rs @@ -3,15 +3,31 @@ use std::path::PathBuf; use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; +use enum_ordinalize::Ordinalize; + #[cfg(feature = "discord-rpc")] pub mod discord_rpc; use crate::config::schema_blanks::prelude::*; use crate::honkai::consts::launcher_dir; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Ordinalize, Serialize, Deserialize)] +pub enum LauncherStyle { + Modern, + Classic +} + +impl Default for LauncherStyle { + #[inline] + fn default() -> Self { + Self::Modern + } +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Launcher { pub language: String, + pub style: LauncherStyle, pub temp: Option, pub repairer: Repairer, @@ -24,6 +40,7 @@ impl Default for Launcher { fn default() -> Self { Self { language: String::from("en-us"), + style: LauncherStyle::default(), temp: launcher_dir().ok(), repairer: Repairer::default(), @@ -43,6 +60,11 @@ impl From<&JsonValue> for Launcher { None => default.language }, + style: match value.get("style") { + Some(value) => serde_json::from_value(value.to_owned()).unwrap_or_default(), + None => default.style + }, + temp: match value.get("temp") { Some(value) => { if value.is_null() { diff --git a/src/honkai/config/schema/mod.rs b/src/honkai/config/schema/mod.rs index 16e1f47..43cb5f2 100644 --- a/src/honkai/config/schema/mod.rs +++ b/src/honkai/config/schema/mod.rs @@ -1,6 +1,12 @@ use serde::{Serialize, Deserialize}; use serde_json::Value as JsonValue; +#[cfg(feature = "components")] +use crate::components::wine::Version as WineVersion; + +#[cfg(feature = "components")] +use crate::components::dxvk::Version as DxvkVersion; + pub mod launcher; pub mod game; pub mod patch; @@ -57,3 +63,23 @@ impl From<&JsonValue> for Schema { } } } + +impl Schema { + #[cfg(feature = "components")] + /// Get selected wine version + pub fn get_selected_wine(&self) -> anyhow::Result> { + match &self.game.wine.selected { + Some(selected) => WineVersion::find_in(&self.components.path, selected), + None => Ok(None) + } + } + + #[cfg(feature = "components")] + /// Get selected dxvk version + pub fn get_selected_dxvk(&self) -> anyhow::Result> { + match wincompatlib::dxvk::Dxvk::get_version(&self.game.wine.prefix)? { + Some(version) => DxvkVersion::find_in(&self.components.path, version), + None => Ok(None) + } + } +} diff --git a/src/game.rs b/src/honkai/game.rs similarity index 58% rename from src/game.rs rename to src/honkai/game.rs index cb22e88..f774ca0 100644 --- a/src/game.rs +++ b/src/honkai/game.rs @@ -1,19 +1,17 @@ use std::process::{Command, Stdio}; -use anime_game_core::prelude::*; -use anime_game_core::genshin::telemetry; -use anime_game_core::genshin::game::Game; +use anime_game_core::honkai::telemetry; -use super::consts; -use super::config; +use crate::config::Config as _; +use crate::honkai::config::Config; +use crate::honkai::config::schema::Schema; -#[cfg(feature = "fps-unlocker")] -use super::fps_unlocker::FpsUnlocker; +use crate::honkai::consts; #[cfg(feature = "discord-rpc")] -use super::discord_rpc::*; +use crate::discord_rpc::*; -fn replace_keywords(command: T, config: &config::Config) -> String { +fn replace_keywords(command: T, config: &Schema) -> String { let wine_build = config.game.wine.builds.join(config.game.wine.selected.as_ref().unwrap()); command.to_string() @@ -21,7 +19,7 @@ fn replace_keywords(command: T, config: &config::Config) -> String .replace("%prefix%", &config.game.wine.prefix.to_string_lossy()) .replace("%temp%", &config.launcher.temp.as_ref().unwrap_or(&std::env::temp_dir()).to_string_lossy()) .replace("%launcher%", &consts::launcher_dir().unwrap().to_string_lossy()) - .replace("%game%", &config.game.path.for_edition(config.launcher.edition).to_string_lossy()) + .replace("%game%", &config.game.path.to_string_lossy()) } /// Try to run the game @@ -31,10 +29,9 @@ fn replace_keywords(command: T, config: &config::Config) -> String pub fn run() -> anyhow::Result<()> { tracing::info!("Preparing to run the game"); - let config = config::get()?; - let game_path = config.game.path.for_edition(config.launcher.edition); + let config = Config::get()?; - if !game_path.exists() { + if !config.game.path.exists() { return Err(anyhow::anyhow!("Game is not installed")); } @@ -52,59 +49,6 @@ pub fn run() -> anyhow::Result<()> { return Err(anyhow::anyhow!("Telemetry server is not disabled: {server}")); } - // Prepare fps unlocker - // 1) Download if needed - // 2) Generate config file - // 3) Generate fpsunlocker.bat from launcher.bat - - #[cfg(feature = "fps-unlocker")] - if config.game.enhancements.fps_unlocker.enabled { - tracing::info!("Preparing FPS unlocker"); - - let unlocker = match FpsUnlocker::from_dir(&config.game.enhancements.fps_unlocker.path) { - Ok(Some(unlocker)) => unlocker, - - other => { - // Ok(None) means unknown version, so we should delete it before downloading newer one - // because otherwise downloader will try to continue downloading "partially downloaded" file - if let Ok(None) = other { - std::fs::remove_file(FpsUnlocker::get_binary_in(&config.game.enhancements.fps_unlocker.path))?; - } - - tracing::info!("Unlocker is not downloaded. Downloading"); - - match FpsUnlocker::download(&config.game.enhancements.fps_unlocker.path) { - Ok(unlocker) => unlocker, - Err(err) => return Err(anyhow::anyhow!("Failed to download FPS unlocker: {err}")) - } - } - }; - - // Generate FPS unlocker config file - if let Err(err) = unlocker.update_config(config.game.enhancements.fps_unlocker.config) { - return Err(anyhow::anyhow!("Failed to update FPS unlocker config: {err}")); - } - - let bat_path = game_path.join("fps_unlocker.bat"); - let original_bat_path = game_path.join("launcher.bat"); - - // Generate fpsunlocker.bat from launcher.bat - std::fs::write(bat_path, std::fs::read_to_string(original_bat_path)? - .replace("start GenshinImpact.exe %*", &format!("start GenshinImpact.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir().to_string_lossy())) - .replace("start YuanShen.exe %*", &format!("start YuanShen.exe %*\n\nZ:\ncd \"{}\"\nstart unlocker.exe", unlocker.dir().to_string_lossy())))?; - } - - // Generate `config.ini` if environment emulation feature is presented - - #[cfg(feature = "environment-emulation")] { - let game = Game::new(game_path); - - std::fs::write( - game_path.join("config.ini"), - config.launcher.environment.generate_config(game.get_version()?.to_string()) - )?; - } - // Prepare bash -c '' let mut bash_command = String::new(); @@ -123,16 +67,12 @@ pub fn run() -> anyhow::Result<()> { bash_command += &run_command; bash_command += " "; - if let Some(virtual_desktop) = config.game.wine.virtual_desktop.get_command() { + if let Some(virtual_desktop) = config.game.wine.virtual_desktop.get_command("honkers") { windows_command += &virtual_desktop; windows_command += " "; } - windows_command += if config.game.enhancements.fps_unlocker.enabled && cfg!(feature = "fps-unlocker") { - "fps_unlocker.bat " - } else { - "launcher.bat " - }; + windows_command += "launcher.bat "; if config.game.wine.borderless { windows_command += "-screen-fullscreen 0 -popupwindow "; @@ -150,7 +90,7 @@ pub fn run() -> anyhow::Result<()> { // Bundle all windows arguments used to run the game into a single file if features.compact_launch { - std::fs::write(game_path.join("compact_launch.bat"), format!("start {windows_command}\nexit"))?; + std::fs::write(config.game.path.join("compact_launch.bat"), format!("start {windows_command}\nexit"))?; windows_command = String::from("compact_launch.bat"); } @@ -185,7 +125,7 @@ pub fn run() -> anyhow::Result<()> { } command.envs(config.game.wine.sync.get_env_vars()); - command.envs(config.game.enhancements.hud.get_env_vars(&config)); + command.envs(config.game.enhancements.hud.get_env_vars(config.game.enhancements.gamescope.enabled)); command.envs(config.game.enhancements.fsr.get_env_vars()); command.envs(config.game.wine.language.get_env_vars()); @@ -200,11 +140,11 @@ pub fn run() -> anyhow::Result<()> { tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); - command.current_dir(game_path).spawn()?.wait_with_output()?; + command.current_dir(config.game.path).spawn()?.wait_with_output()?; #[cfg(feature = "discord-rpc")] let rpc = if config.launcher.discord_rpc.enabled { - Some(DiscordRpc::new(config.launcher.discord_rpc)) + Some(DiscordRpc::new(config.launcher.discord_rpc.into())) } else { None }; diff --git a/src/honkai/mod.rs b/src/honkai/mod.rs index 975ffbb..979c3bd 100644 --- a/src/honkai/mod.rs +++ b/src/honkai/mod.rs @@ -5,3 +5,6 @@ pub mod states; #[cfg(feature = "config")] pub mod config; + +#[cfg(feature = "game")] +pub mod game; diff --git a/src/lib.rs b/src/lib.rs index a1c0831..6c8d79b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,11 +15,8 @@ pub mod config; #[cfg(feature = "components")] pub mod components; -#[cfg(feature = "game")] -// pub mod game; - #[cfg(feature = "discord-rpc")] -// pub mod discord_rpc; +pub mod discord_rpc; pub const VERSION: &str = env!("CARGO_PKG_VERSION");