From 8bec171c5d8616cf680eccaa70c8b81272a51ff1 Mon Sep 17 00:00:00 2001 From: Observer KRypt0n_ Date: Fri, 1 Jul 2022 12:20:08 +0200 Subject: [PATCH] Changed config file format and struture - added `Config::try_get_wine_executable` method - fixed launher freezing when running the game --- Cargo.toml | 2 +- src/lib/config.rs | 150 ++++++++++++++++++++++++++++++++++++++-------- src/lib/consts.rs | 2 +- src/lib/game.rs | 17 ++++-- 4 files changed, 139 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bd2e814..484a3fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,6 @@ libadwaita = "0.1" anime-game-core = { path = "anime-game-core", features = ["all"] } serde = { version = "1.0", features = ["derive"] } -toml = "0.5.9" +serde_json = "1.0" dirs = "4.0.0" diff --git a/src/lib/config.rs b/src/lib/config.rs index 3049723..0fc5103 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -5,7 +5,7 @@ use std::io::{Error, ErrorKind, Write}; use serde::{Serialize, Deserialize}; -use super::consts::config_file; +use super::consts::*; pub fn get() -> Result { match config_file() { @@ -13,13 +13,13 @@ pub fn get() -> Result { // Try to read config if the file exists if Path::new(&path).exists() { let mut file = File::open(path)?; - let mut toml = String::new(); + let mut json = String::new(); - file.read_to_string(&mut toml)?; + file.read_to_string(&mut json)?; - match toml::from_str::(&toml) { - Ok(toml) => Ok(toml), - Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to decode data from toml format: {}", err.to_string()))) + match serde_json::from_str::(&json) { + Ok(json) => Ok(json), + Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to decode data from json format: {}", err.to_string()))) } } @@ -39,13 +39,13 @@ pub fn update(config: Config) -> Result<(), Error> { Some(path) => { let mut file = File::create(&path)?; - match toml::to_string(&config) { - Ok(toml) => { - file.write_all(&mut toml.as_bytes())?; + match serde_json::to_string_pretty(&config) { + Ok(json) => { + file.write_all(&mut json.as_bytes())?; Ok(()) }, - Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to encode data into toml format: {}", err.to_string()))) + Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to encode data into json format: {}", err.to_string()))) } }, None => Err(Error::new(ErrorKind::NotFound, format!("Failed to get config file path"))) @@ -54,35 +54,137 @@ pub fn update(config: Config) -> Result<(), Error> { #[derive(Debug, Serialize, Deserialize, Default)] pub struct Config { - pub paths: Paths, - pub patch: Patch, - pub wine: Wine + pub launcher: Launcher, + pub game: Game, + pub patch: Patch } -#[derive(Debug, Serialize, Deserialize, Default)] -pub struct Paths { - pub game: String, - pub patch: String +impl Config { + /// Try to get a path to the wine executable based on `game.wine.builds` and `game.wine.selected` + pub fn try_get_wine_executable(&self) -> Option { + match &self.game.wine.selected { + Some(selected) => { + // Most of wine builds + let path = format!("{}/{}/bin/wine", &self.game.wine.builds, &selected); + + if Path::new(&path).exists() { + return Some(path); + } + + // Proton-based builds + let path = format!("{}/{}/files/bin/wine", &self.game.wine.builds, &selected); + + if Path::new(&path).exists() { + return Some(path); + } + + // ???? + None + }, + None => None + } + } } -#[derive(Debug, Serialize, Deserialize, Default)] +#[derive(Debug, Serialize, Deserialize)] +pub struct Launcher { + pub language: String +} + +impl Default for Launcher { + fn default() -> Self { + Self { + language: String::from("en-us") + } + } +} + +#[derive(Debug, Serialize, Deserialize)] pub struct Patch { - pub hosts: Vec + pub path: String, + pub servers: Vec +} + +impl Default for Patch { + fn default() -> Self { + Self { + path: match launcher_dir() { + Some(dir) => format!("{}/patch", dir), + None => String::new() + }, + servers: Vec::new() + } + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Game { + pub path: String, + pub voices: Vec, + pub wine: Wine, + pub enhancements: Enhancements, + pub environment: HashMap +} + +impl Default for Game { + fn default() -> Self { + Self { + path: match launcher_dir() { + Some(dir) => format!("{}/game/drive_c/Program Files/Genshin Impact", dir), + None => String::new() + }, + voices: vec![ + String::from("en-us") + ], + wine: Wine::default(), + enhancements: Enhancements::default(), + environment: HashMap::new() + } + } } #[derive(Debug, Serialize, Deserialize)] pub struct Wine { pub prefix: String, - pub executable: String, - pub environment: HashMap + pub builds: String, + pub selected: Option, + pub sync: String } impl Default for Wine { fn default() -> Self { Self { - prefix: String::new(), - executable: String::new(), - environment: HashMap::new() + prefix: match launcher_dir() { + Some(dir) => format!("{}/game", dir), + None => String::new() + }, + builds: match launcher_dir() { + Some(dir) => format!("{}/runners", dir), + None => String::new() + }, + selected: None, + sync: String::from("esync") + } + } +} + +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct Enhancements { + pub fsr: Fsr, + pub gamemode: bool +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct Fsr { + pub strength: u8, + pub enabled: bool +} + +impl Default for Fsr { + fn default() -> Self { + Self { + strength: 3, + enabled: false } } } diff --git a/src/lib/consts.rs b/src/lib/consts.rs index f2d9895..e54d1c2 100644 --- a/src/lib/consts.rs +++ b/src/lib/consts.rs @@ -25,7 +25,7 @@ pub fn config_file() -> Option { Some(value) => value.clone(), None => { let value = match launcher_dir() { - Some(dir) => Some(format!("{}/config.toml", dir)), + Some(dir) => Some(format!("{}/config.json", dir)), None => None }; diff --git a/src/lib/game.rs b/src/lib/game.rs index 0ce154d..a1ba9b7 100644 --- a/src/lib/game.rs +++ b/src/lib/game.rs @@ -7,16 +7,21 @@ use super::config; pub fn run() -> Result<(), Error> { let config = config::get()?; - if Path::new(&config.paths.game).exists() { + if !Path::new(&config.game.path).exists() { return Err(Error::new(ErrorKind::Other, "Game is not installed")); } - Command::new(config.wine.executable) - .env("WINEPREFIX", &config.wine.prefix) - .envs(config.wine.environment) - .current_dir(config.paths.game) + let wine_executable = match config.try_get_wine_executable() { + Some(path) => path, + None => return Err(Error::new(ErrorKind::Other, "Couldn't find wine executable")) + }; + + Command::new(wine_executable) + .env("WINEPREFIX", config.game.wine.prefix) + .envs(config.game.environment) + .current_dir(config.game.path) .arg("launcher.bat") - .output()?; + .spawn()?; Ok(()) }