Changed config file format and struture

- added `Config::try_get_wine_executable` method
- fixed launher freezing when running the game
This commit is contained in:
Observer KRypt0n_ 2022-07-01 12:20:08 +02:00
parent 1eed56e53a
commit 8bec171c5d
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
4 changed files with 139 additions and 32 deletions

View file

@ -14,6 +14,6 @@ libadwaita = "0.1"
anime-game-core = { path = "anime-game-core", features = ["all"] } anime-game-core = { path = "anime-game-core", features = ["all"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "0.5.9" serde_json = "1.0"
dirs = "4.0.0" dirs = "4.0.0"

View file

@ -5,7 +5,7 @@ use std::io::{Error, ErrorKind, Write};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use super::consts::config_file; use super::consts::*;
pub fn get() -> Result<Config, Error> { pub fn get() -> Result<Config, Error> {
match config_file() { match config_file() {
@ -13,13 +13,13 @@ pub fn get() -> Result<Config, Error> {
// Try to read config if the file exists // Try to read config if the file exists
if Path::new(&path).exists() { if Path::new(&path).exists() {
let mut file = File::open(path)?; 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::<Config>(&toml) { match serde_json::from_str::<Config>(&json) {
Ok(toml) => Ok(toml), Ok(json) => Ok(json),
Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to decode data from toml format: {}", err.to_string()))) 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) => { Some(path) => {
let mut file = File::create(&path)?; let mut file = File::create(&path)?;
match toml::to_string(&config) { match serde_json::to_string_pretty(&config) {
Ok(toml) => { Ok(json) => {
file.write_all(&mut toml.as_bytes())?; file.write_all(&mut json.as_bytes())?;
Ok(()) 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"))) 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)] #[derive(Debug, Serialize, Deserialize, Default)]
pub struct Config { pub struct Config {
pub paths: Paths, pub launcher: Launcher,
pub patch: Patch, pub game: Game,
pub wine: Wine pub patch: Patch
} }
#[derive(Debug, Serialize, Deserialize, Default)] impl Config {
pub struct Paths { /// Try to get a path to the wine executable based on `game.wine.builds` and `game.wine.selected`
pub game: String, pub fn try_get_wine_executable(&self) -> Option<String> {
pub patch: String 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);
} }
#[derive(Debug, Serialize, Deserialize, Default)] // 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)]
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 struct Patch {
pub hosts: Vec<String> pub path: String,
pub servers: Vec<String>
}
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<String>,
pub wine: Wine,
pub enhancements: Enhancements,
pub environment: HashMap<String, String>
}
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)] #[derive(Debug, Serialize, Deserialize)]
pub struct Wine { pub struct Wine {
pub prefix: String, pub prefix: String,
pub executable: String, pub builds: String,
pub environment: HashMap<String, String> pub selected: Option<String>,
pub sync: String
} }
impl Default for Wine { impl Default for Wine {
fn default() -> Self { fn default() -> Self {
Self { Self {
prefix: String::new(), prefix: match launcher_dir() {
executable: String::new(), Some(dir) => format!("{}/game", dir),
environment: HashMap::new() 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
} }
} }
} }

View file

@ -25,7 +25,7 @@ pub fn config_file() -> Option<String> {
Some(value) => value.clone(), Some(value) => value.clone(),
None => { None => {
let value = match launcher_dir() { let value = match launcher_dir() {
Some(dir) => Some(format!("{}/config.toml", dir)), Some(dir) => Some(format!("{}/config.json", dir)),
None => None None => None
}; };

View file

@ -7,16 +7,21 @@ use super::config;
pub fn run() -> Result<(), Error> { pub fn run() -> Result<(), Error> {
let config = config::get()?; 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")); return Err(Error::new(ErrorKind::Other, "Game is not installed"));
} }
Command::new(config.wine.executable) let wine_executable = match config.try_get_wine_executable() {
.env("WINEPREFIX", &config.wine.prefix) Some(path) => path,
.envs(config.wine.environment) None => return Err(Error::new(ErrorKind::Other, "Couldn't find wine executable"))
.current_dir(config.paths.game) };
Command::new(wine_executable)
.env("WINEPREFIX", config.game.wine.prefix)
.envs(config.game.environment)
.current_dir(config.game.path)
.arg("launcher.bat") .arg("launcher.bat")
.output()?; .spawn()?;
Ok(()) Ok(())
} }