diff --git a/src/games/genshin/game.rs b/src/games/genshin/game.rs index 1069139..3788573 100644 --- a/src/games/genshin/game.rs +++ b/src/games/genshin/game.rs @@ -1,3 +1,4 @@ +use std::io::{Read, Write}; use std::process::{Command, Stdio}; use std::path::PathBuf; @@ -302,9 +303,51 @@ pub fn run() -> anyhow::Result<()> { // We use real current dir here because sandboxed one // obviously doesn't exist - command.current_dir(config.game.path.for_edition(config.launcher.edition)) - .spawn()?.wait_with_output()?; - + let mut child = command.current_dir(config.game.path.for_edition(config.launcher.edition)) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // Create new game.log file to log all the game output + let mut game_output = std::fs::File::create(consts::launcher_dir()?.join("game.log"))?; + + // Log process output while it's running + while child.try_wait()?.is_none() { + std::thread::sleep(std::time::Duration::from_secs(3)); + + // Redirect stdout to the game.log file + if let Some(stdout) = &mut child.stdout { + let mut buf = Vec::new(); + + stdout.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b" [stdout] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + // Redirect stdout to the game.log file + if let Some(stderr) = &mut child.stderr { + let mut buf = Vec::new(); + + stderr.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b"[!] [stderr] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + #[cfg(feature = "discord-rpc")] + if let Some(rpc) = &rpc { + rpc.update(RpcUpdates::Update)?; + } + } + + // Workaround for fast process closing (is it still a thing?) loop { std::thread::sleep(std::time::Duration::from_secs(3)); diff --git a/src/games/honkai/game.rs b/src/games/honkai/game.rs index 0689f31..415297c 100644 --- a/src/games/honkai/game.rs +++ b/src/games/honkai/game.rs @@ -1,3 +1,4 @@ +use std::io::{Read, Write}; use std::process::{Command, Stdio}; use std::path::PathBuf; @@ -231,20 +232,7 @@ pub fn run() -> anyhow::Result<()> { Sessions::apply(current, config.get_wine_prefix_path())?; } - // Run command - - let variables = command - .get_envs() - .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) - .fold(String::new(), |acc, env| acc + " " + &env); - - tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); - - // We use real current dir here because sandboxed one - // obviously doesn't exist - command.current_dir(game_path) - .spawn()?.wait_with_output()?; - + // Start Discord RPC just before the game #[cfg(feature = "discord-rpc")] let rpc = if config.launcher.discord_rpc.enabled { Some(DiscordRpc::new(config.launcher.discord_rpc.clone().into())) @@ -257,6 +245,62 @@ pub fn run() -> anyhow::Result<()> { rpc.update(RpcUpdates::Connect)?; } + // Run command + + let variables = command + .get_envs() + .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) + .fold(String::new(), |acc, env| acc + " " + &env); + + tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); + + // We use real current dir here because sandboxed one + // obviously doesn't exist + let mut child = command.current_dir(game_path) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // Create new game.log file to log all the game output + let mut game_output = std::fs::File::create(consts::launcher_dir()?.join("game.log"))?; + + // Log process output while it's running + while child.try_wait()?.is_none() { + std::thread::sleep(std::time::Duration::from_secs(3)); + + // Redirect stdout to the game.log file + if let Some(stdout) = &mut child.stdout { + let mut buf = Vec::new(); + + stdout.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b" [stdout] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + // Redirect stdout to the game.log file + if let Some(stderr) = &mut child.stderr { + let mut buf = Vec::new(); + + stderr.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b"[!] [stderr] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + #[cfg(feature = "discord-rpc")] + if let Some(rpc) = &rpc { + rpc.update(RpcUpdates::Update)?; + } + } + + // Workaround for fast process closing (is it still a thing?) loop { std::thread::sleep(std::time::Duration::from_secs(3)); diff --git a/src/games/pgr/game.rs b/src/games/pgr/game.rs index 0a1c3bf..7cbd69c 100644 --- a/src/games/pgr/game.rs +++ b/src/games/pgr/game.rs @@ -222,20 +222,7 @@ pub fn run() -> anyhow::Result<()> { Sessions::apply(current, config.get_wine_prefix_path())?; } - // Run command - - let variables = command - .get_envs() - .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) - .fold(String::new(), |acc, env| acc + " " + &env); - - tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); - - // We use real current dir here because sandboxed one - // obviously doesn't exist - command.current_dir(&config.game.path) - .spawn()?.wait_with_output()?; - + // Start Discord RPC just before the game #[cfg(feature = "discord-rpc")] let rpc = if config.launcher.discord_rpc.enabled { Some(DiscordRpc::new(config.launcher.discord_rpc.clone().into())) @@ -248,6 +235,62 @@ pub fn run() -> anyhow::Result<()> { rpc.update(RpcUpdates::Connect)?; } + // Run command + + let variables = command + .get_envs() + .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) + .fold(String::new(), |acc, env| acc + " " + &env); + + tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); + + // We use real current dir here because sandboxed one + // obviously doesn't exist + let mut child = command.current_dir(config.game.path) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // Create new game.log file to log all the game output + let mut game_output = std::fs::File::create(consts::launcher_dir()?.join("game.log"))?; + + // Log process output while it's running + while child.try_wait()?.is_none() { + std::thread::sleep(std::time::Duration::from_secs(3)); + + // Redirect stdout to the game.log file + if let Some(stdout) = &mut child.stdout { + let mut buf = Vec::new(); + + stdout.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b" [stdout] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + // Redirect stdout to the game.log file + if let Some(stderr) = &mut child.stderr { + let mut buf = Vec::new(); + + stderr.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b"[!] [stderr] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + #[cfg(feature = "discord-rpc")] + if let Some(rpc) = &rpc { + rpc.update(RpcUpdates::Update)?; + } + } + + // Workaround for fast process closing (is it still a thing?) loop { std::thread::sleep(std::time::Duration::from_secs(3)); diff --git a/src/games/star_rail/game.rs b/src/games/star_rail/game.rs index 8819156..a43be00 100644 --- a/src/games/star_rail/game.rs +++ b/src/games/star_rail/game.rs @@ -233,20 +233,7 @@ pub fn run() -> anyhow::Result<()> { Sessions::apply(current, config.get_wine_prefix_path())?; } - // Run command - - let variables = command - .get_envs() - .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) - .fold(String::new(), |acc, env| acc + " " + &env); - - tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); - - // We use real current dir here because sandboxed one - // obviously doesn't exist - command.current_dir(game_path) - .spawn()?.wait_with_output()?; - + // Start Discord RPC just before the game #[cfg(feature = "discord-rpc")] let rpc = if config.launcher.discord_rpc.enabled { Some(DiscordRpc::new(config.launcher.discord_rpc.clone().into())) @@ -259,6 +246,62 @@ pub fn run() -> anyhow::Result<()> { rpc.update(RpcUpdates::Connect)?; } + // Run command + + let variables = command + .get_envs() + .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) + .fold(String::new(), |acc, env| acc + " " + &env); + + tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); + + // We use real current dir here because sandboxed one + // obviously doesn't exist + let mut child = command.current_dir(config.game.path.for_edition(config.launcher.edition)) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // Create new game.log file to log all the game output + let mut game_output = std::fs::File::create(consts::launcher_dir()?.join("game.log"))?; + + // Log process output while it's running + while child.try_wait()?.is_none() { + std::thread::sleep(std::time::Duration::from_secs(3)); + + // Redirect stdout to the game.log file + if let Some(stdout) = &mut child.stdout { + let mut buf = Vec::new(); + + stdout.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b" [stdout] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + // Redirect stdout to the game.log file + if let Some(stderr) = &mut child.stderr { + let mut buf = Vec::new(); + + stderr.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b"[!] [stderr] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + #[cfg(feature = "discord-rpc")] + if let Some(rpc) = &rpc { + rpc.update(RpcUpdates::Update)?; + } + } + + // Workaround for fast process closing (is it still a thing?) loop { std::thread::sleep(std::time::Duration::from_secs(3)); diff --git a/src/games/wuwa/game.rs b/src/games/wuwa/game.rs index 5a3d800..9d5464a 100644 --- a/src/games/wuwa/game.rs +++ b/src/games/wuwa/game.rs @@ -214,20 +214,6 @@ pub fn run() -> anyhow::Result<()> { command.envs(&config.game.environment); - // Run command - - let variables = command - .get_envs() - .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) - .fold(String::new(), |acc, env| acc + " " + &env); - - tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); - - // We use real current dir here because sandboxed one - // obviously doesn't exist - command.current_dir(&config.game.path.for_edition(config.launcher.edition)) - .spawn()?.wait_with_output()?; - #[cfg(feature = "discord-rpc")] let rpc = if config.launcher.discord_rpc.enabled { Some(DiscordRpc::new(config.launcher.discord_rpc.clone().into())) @@ -240,6 +226,62 @@ pub fn run() -> anyhow::Result<()> { rpc.update(RpcUpdates::Connect)?; } + // Run command + + let variables = command + .get_envs() + .map(|(key, value)| format!("{}=\"{}\"", key.to_string_lossy(), value.unwrap_or_default().to_string_lossy())) + .fold(String::new(), |acc, env| acc + " " + &env); + + tracing::info!("Running the game with command: {variables} bash -c \"{bash_command}\""); + + // We use real current dir here because sandboxed one + // obviously doesn't exist + let mut child = command.current_dir(config.game.path.for_edition(config.launcher.edition)) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // Create new game.log file to log all the game output + let mut game_output = std::fs::File::create(consts::launcher_dir()?.join("game.log"))?; + + // Log process output while it's running + while child.try_wait()?.is_none() { + std::thread::sleep(std::time::Duration::from_secs(3)); + + // Redirect stdout to the game.log file + if let Some(stdout) = &mut child.stdout { + let mut buf = Vec::new(); + + stdout.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b" [stdout] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + // Redirect stdout to the game.log file + if let Some(stderr) = &mut child.stderr { + let mut buf = Vec::new(); + + stderr.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b"[!] [stderr] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + #[cfg(feature = "discord-rpc")] + if let Some(rpc) = &rpc { + rpc.update(RpcUpdates::Update)?; + } + } + + // Workaround for fast process closing (is it still a thing?) loop { std::thread::sleep(std::time::Duration::from_secs(3)); diff --git a/src/games/zzz/game.rs b/src/games/zzz/game.rs index 64c65d3..8a5e6c4 100644 --- a/src/games/zzz/game.rs +++ b/src/games/zzz/game.rs @@ -255,9 +255,51 @@ pub fn run() -> anyhow::Result<()> { // We use real current dir here because sandboxed one // obviously doesn't exist - command.current_dir(config.game.path.for_edition(config.launcher.edition)) - .spawn()?.wait_with_output()?; - + let mut child = command.current_dir(config.game.path.for_edition(config.launcher.edition)) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // Create new game.log file to log all the game output + let mut game_output = std::fs::File::create(consts::launcher_dir()?.join("game.log"))?; + + // Log process output while it's running + while child.try_wait()?.is_none() { + std::thread::sleep(std::time::Duration::from_secs(3)); + + // Redirect stdout to the game.log file + if let Some(stdout) = &mut child.stdout { + let mut buf = Vec::new(); + + stdout.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b" [stdout] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + // Redirect stdout to the game.log file + if let Some(stderr) = &mut child.stderr { + let mut buf = Vec::new(); + + stderr.read_to_end(&mut buf)?; + + for line in buf.split(|c| c == &b'\n') { + game_output.write_all(b"[!] [stderr] ")?; + game_output.write_all(line)?; + game_output.write_all(b"\n")?; + } + } + + #[cfg(feature = "discord-rpc")] + if let Some(rpc) = &rpc { + rpc.update(RpcUpdates::Update)?; + } + } + + // Workaround for fast process closing (is it still a thing?) loop { std::thread::sleep(std::time::Duration::from_secs(3));