feat: several changes

- Reworked config properties parsing;
- Improved multi-region support;
- Removed legacy compatibility code (genshin game paths)
This commit is contained in:
Observer KRypt0n_ 2023-08-03 17:55:41 +02:00
parent d72eb796cf
commit 8572d551f8
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
21 changed files with 327 additions and 302 deletions

View file

@ -22,13 +22,10 @@ macro_rules! config_impl_dxvk_schema {
let default = Self::default(); let default = Self::default();
Self { Self {
builds: match value.get("builds") { builds: value.get("builds")
Some(value) => match value.as_str() { .and_then(|value| value.as_str())
Some(value) => PathBuf::from(value), .map(PathBuf::from)
None => default.builds .unwrap_or(default.builds),
},
None => default.builds
}
} }
} }
} }

View file

@ -12,15 +12,13 @@ impl From<&JsonValue> for Framerate {
let default = Self::default(); let default = Self::default();
Self { Self {
focused: match value.get("focused") { focused: value.get("focused")
Some(value) => value.as_u64().unwrap_or(default.focused), .and_then(JsonValue::as_u64)
None => default.focused .unwrap_or(default.focused),
},
unfocused: match value.get("unfocused") { unfocused: value.get("unfocused")
Some(value) => value.as_u64().unwrap_or(default.unfocused), .and_then(JsonValue::as_u64)
None => default.unfocused .unwrap_or(default.unfocused)
}
} }
} }
} }

View file

@ -49,45 +49,37 @@ impl From<&JsonValue> for Gamescope {
let default = Self::default(); let default = Self::default();
Self { Self {
enabled: match value.get("enabled") { enabled: value.get("enabled")
Some(value) => value.as_bool().unwrap_or(default.enabled), .and_then(JsonValue::as_bool)
None => default.enabled .unwrap_or(default.enabled),
},
game: match value.get("game") { game: value.get("game")
Some(value) => Size::from(value), .map(Size::from)
None => default.game .unwrap_or(default.game),
},
gamescope: match value.get("gamescope") { gamescope: value.get("gamescope")
Some(value) => Size::from(value), .map(Size::from)
None => default.gamescope .unwrap_or(default.gamescope),
},
framerate: match value.get("framerate") { framerate: value.get("framerate")
Some(value) => Framerate::from(value), .map(Framerate::from)
None => default.framerate .unwrap_or(default.framerate),
},
integer_scaling: match value.get("integer_scaling") { integer_scaling: value.get("integer_scaling")
Some(value) => value.as_bool().unwrap_or(default.integer_scaling), .and_then(JsonValue::as_bool)
None => default.integer_scaling .unwrap_or(default.integer_scaling),
},
fsr: match value.get("fsr") { fsr: value.get("fsr")
Some(value) => value.as_bool().unwrap_or(default.fsr), .and_then(JsonValue::as_bool)
None => default.fsr .unwrap_or(default.fsr),
},
nis: match value.get("nis") { nis: value.get("nis")
Some(value) => value.as_bool().unwrap_or(default.nis), .and_then(JsonValue::as_bool)
None => default.nis .unwrap_or(default.nis),
},
window_type: match value.get("window_type") { window_type: value.get("window_type")
Some(value) => WindowType::from(value), .map(WindowType::from)
None => default.window_type .unwrap_or(default.window_type)
}
} }
} }
} }
@ -99,6 +91,7 @@ fn is_legacy_version() -> bool {
Command::new("gamescope").arg("--help").output() Command::new("gamescope").arg("--help").output()
// if no --filter, then it's legacy version // if no --filter, then it's legacy version
// also for whatever reason --help is printed to stderr
.map(|help| !String::from_utf8_lossy(&help.stderr).contains("-F, --filter")) .map(|help| !String::from_utf8_lossy(&help.stderr).contains("-F, --filter"))
// If failed to launch gamescope, then yes, it's legacy (it's not but meh) // If failed to launch gamescope, then yes, it's legacy (it's not but meh)

View file

@ -12,15 +12,13 @@ impl From<&JsonValue> for Size {
let default = Self::default(); let default = Self::default();
Self { Self {
width: match value.get("width") { width: value.get("width")
Some(value) => value.as_u64().unwrap_or(default.width), .and_then(JsonValue::as_u64)
None => default.width .unwrap_or(default.width),
},
height: match value.get("height") { height: value.get("height")
Some(value) => value.as_u64().unwrap_or(default.height), .and_then(JsonValue::as_u64)
None => default.height .unwrap_or(default.height)
}
} }
} }
} }

View file

@ -22,15 +22,13 @@ impl From<&JsonValue> for Repairer {
let default = Self::default(); let default = Self::default();
Self { Self {
threads: match value.get("threads") { threads: value.get("threads")
Some(value) => value.as_u64().unwrap_or(default.threads), .and_then(JsonValue::as_u64)
None => default.threads .unwrap_or(default.threads),
},
fast: match value.get("fast") { fast: value.get("fast")
Some(value) => value.as_bool().unwrap_or(default.fast), .and_then(JsonValue::as_bool)
None => default.fast .unwrap_or(default.fast)
}
} }
} }
} }

View file

@ -47,15 +47,13 @@ impl From<&JsonValue> for Sandbox {
let default = Self::default(); let default = Self::default();
Self { Self {
enabled: match value.get("enabled") { enabled: value.get("enabled")
Some(value) => value.as_bool().unwrap_or(default.enabled), .and_then(JsonValue::as_bool)
None => default.enabled .unwrap_or(default.enabled),
},
isolate_home: match value.get("isolate_home") { isolate_home: value.get("isolate_home")
Some(value) => value.as_bool().unwrap_or(default.isolate_home), .and_then(JsonValue::as_bool)
None => default.isolate_home .unwrap_or(default.isolate_home),
},
hostname: match value.get("hostname") { hostname: match value.get("hostname") {
Some(value) => { Some(value) => {
@ -88,25 +86,19 @@ impl From<&JsonValue> for Sandbox {
private: match value.get("private") { private: match value.get("private") {
Some(value) => match value.as_array() { Some(value) => match value.as_array() {
Some(values) => { Some(values) => {
let mut private = Vec::new(); values.iter()
.flat_map(|value| value.as_str())
for value in values { .map(|value| value.to_string())
if let Some(server) = value.as_str() { .collect()
private.push(server.to_string());
}
}
private
}, },
None => default.private None => default.private
}, },
None => default.private None => default.private
}, },
mounts: match value.get("mounts") { mounts: value.get("mounts")
Some(value) => Mounts::from(value), .map(Mounts::from)
None => default.mounts .unwrap_or(default.mounts)
}
} }
} }
} }

View file

@ -48,21 +48,15 @@ macro_rules! config_impl_wine_schema {
let default = Self::default(); let default = Self::default();
Self { Self {
prefix: match value.get("prefix") { prefix: value.get("prefix")
Some(value) => match value.as_str() { .and_then(|value| value.as_str())
Some(value) => PathBuf::from(value), .map(PathBuf::from)
None => default.prefix .unwrap_or(default.prefix),
},
None => default.prefix
},
builds: match value.get("builds") { builds: value.get("builds")
Some(value) => match value.as_str() { .and_then(|value| value.as_str())
Some(value) => PathBuf::from(value), .map(PathBuf::from)
None => default.builds .unwrap_or(default.builds),
},
None => default.builds
},
selected: match value.get("selected") { selected: match value.get("selected") {
Some(value) => { Some(value) => {
@ -78,30 +72,25 @@ macro_rules! config_impl_wine_schema {
None => default.selected None => default.selected
}, },
sync: match value.get("sync") { sync: value.get("sync")
Some(value) => WineSync::from(value), .map(WineSync::from)
None => default.sync .unwrap_or(default.sync),
},
language: match value.get("language") { language: value.get("language")
Some(value) => WineLang::from(value), .map(WineLang::from)
None => default.language .unwrap_or(default.language),
},
borderless: match value.get("borderless") { borderless: value.get("borderless")
Some(value) => value.as_bool().unwrap_or(default.borderless), .and_then(|value| value.as_bool())
None => default.borderless .unwrap_or(default.borderless),
},
virtual_desktop: match value.get("virtual_desktop") { virtual_desktop: value.get("virtual_desktop")
Some(value) => VirtualDesktop::from(value), .map(VirtualDesktop::from)
None => default.virtual_desktop .unwrap_or(default.virtual_desktop),
},
shared_libraries: match value.get("shared_libraries") { shared_libraries: value.get("shared_libraries")
Some(value) => SharedLibraries::from(value), .map(SharedLibraries::from)
None => default.shared_libraries .unwrap_or(default.shared_libraries),
},
} }
} }
} }

View file

@ -26,20 +26,17 @@ impl From<&JsonValue> for VirtualDesktop {
let default = Self::default(); let default = Self::default();
Self { Self {
enabled: match value.get("enabled") { enabled: value.get("enabled")
Some(value) => value.as_bool().unwrap_or(default.enabled), .and_then(JsonValue::as_bool)
None => default.enabled .unwrap_or(default.enabled),
},
width: match value.get("width") { width: value.get("width")
Some(value) => value.as_u64().unwrap_or(default.width), .and_then(JsonValue::as_u64)
None => default.width .unwrap_or(default.width),
},
height: match value.get("height") { height: value.get("height")
Some(value) => value.as_u64().unwrap_or(default.height), .and_then(JsonValue::as_u64)
None => default.height .unwrap_or(default.height)
}
} }
} }
} }

View file

@ -23,31 +23,26 @@ impl From<&JsonValue> for Enhancements {
let default = Self::default(); let default = Self::default();
Self { Self {
fsr: match value.get("fsr") { fsr: value.get("fsr")
Some(value) => Fsr::from(value), .map(Fsr::from)
None => default.fsr .unwrap_or(default.fsr),
},
gamemode: match value.get("gamemode") { gamemode: value.get("gamemode")
Some(value) => value.as_bool().unwrap_or(default.gamemode), .and_then(JsonValue::as_bool)
None => default.gamemode .unwrap_or(default.gamemode),
},
hud: match value.get("hud") { hud: value.get("hud")
Some(value) => HUD::from(value), .map(HUD::from)
None => default.hud .unwrap_or(default.hud),
},
#[cfg(feature = "fps-unlocker")] #[cfg(feature = "fps-unlocker")]
fps_unlocker: match value.get("fps_unlocker") { fps_unlocker: value.get("fps_unlocker")
Some(value) => FpsUnlocker::from(value), .map(FpsUnlocker::from)
None => default.fps_unlocker .unwrap_or(default.fps_unlocker),
},
gamescope: match value.get("gamescope") { gamescope: value.get("gamescope")
Some(value) => Gamescope::from(value), .map(Gamescope::from)
None => default.gamescope .unwrap_or(default.gamescope)
}
} }
} }
} }

View file

@ -65,10 +65,9 @@ impl From<&JsonValue> for Game {
let default = Self::default(); let default = Self::default();
Self { Self {
path: match value.get("path") { path: value.get("path")
Some(value) => Paths::from(value), .map(Paths::from)
None => default.path .unwrap_or(default.path),
},
voices: match value.get("voices") { voices: match value.get("voices") {
Some(value) => match value.as_array() { Some(value) => match value.as_array() {
@ -88,20 +87,17 @@ impl From<&JsonValue> for Game {
None => default.voices None => default.voices
}, },
wine: match value.get("wine") { wine: value.get("wine")
Some(value) => Wine::from(value), .map(Wine::from)
None => default.wine .unwrap_or(default.wine),
},
dxvk: match value.get("dxvk") { dxvk: value.get("dxvk")
Some(value) => Dxvk::from(value), .map(Dxvk::from)
None => default.dxvk .unwrap_or(default.dxvk),
},
enhancements: match value.get("enhancements") { enhancements: value.get("enhancements")
Some(value) => Enhancements::from(value), .map(Enhancements::from)
None => default.enhancements .unwrap_or(default.enhancements),
},
environment: match value.get("environment") { environment: match value.get("environment") {
Some(value) => match value.as_object() { Some(value) => match value.as_object() {

View file

@ -39,38 +39,16 @@ impl From<&JsonValue> for Paths {
fn from(value: &JsonValue) -> Self { fn from(value: &JsonValue) -> Self {
let default = Self::default(); let default = Self::default();
// SDK 0.5.11 (launcher 3.3.0) and earlier Self {
if value.is_string() { global: value.get("global")
let path = PathBuf::from(value.as_str().unwrap()); .and_then(JsonValue::as_str)
.map(PathBuf::from)
.unwrap_or(default.global),
Self { china: value.get("china")
china: match path.parent() { .and_then(JsonValue::as_str)
Some(parent) => parent.join(concat!("Yu", "anS", "hen")), .map(PathBuf::from)
None => default.china .unwrap_or(default.china),
},
global: path
}
}
// SDK 0.5.12 and later
else {
Self {
global: match value.get("global") {
Some(value) => match value.as_str() {
Some(value) => PathBuf::from(value),
None => default.global
},
None => default.global
},
china: match value.get("china") {
Some(value) => match value.as_str() {
Some(value) => PathBuf::from(value),
None => default.china
},
None => default.china
}
}
} }
} }
} }

View file

@ -16,25 +16,21 @@ impl From<&JsonValue> for Enhancements {
let default = Self::default(); let default = Self::default();
Self { Self {
fsr: match value.get("fsr") { fsr: value.get("fsr")
Some(value) => Fsr::from(value), .map(Fsr::from)
None => default.fsr .unwrap_or(default.fsr),
},
gamemode: match value.get("gamemode") { gamemode: value.get("gamemode")
Some(value) => value.as_bool().unwrap_or(default.gamemode), .and_then(JsonValue::as_bool)
None => default.gamemode .unwrap_or(default.gamemode),
},
hud: match value.get("hud") { hud: value.get("hud")
Some(value) => HUD::from(value), .map(HUD::from)
None => default.hud .unwrap_or(default.hud),
},
gamescope: match value.get("gamescope") { gamescope: value.get("gamescope")
Some(value) => Gamescope::from(value), .map(Gamescope::from)
None => default.gamescope .unwrap_or(default.gamescope)
}
} }
} }
} }

View file

@ -10,11 +10,13 @@ use crate::honkai::consts::launcher_dir;
crate::config_impl_wine_schema!(launcher_dir); crate::config_impl_wine_schema!(launcher_dir);
crate::config_impl_dxvk_schema!(launcher_dir); crate::config_impl_dxvk_schema!(launcher_dir);
pub mod paths;
pub mod enhancements; pub mod enhancements;
pub mod prelude { pub mod prelude {
pub use super::Wine; pub use super::Wine;
pub use super::Dxvk; pub use super::Dxvk;
pub use super::paths::Paths;
pub use super::enhancements::Enhancements; pub use super::enhancements::Enhancements;
} }
@ -22,7 +24,7 @@ use prelude::*;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Game { pub struct Game {
pub path: PathBuf, pub path: Paths,
pub wine: Wine, pub wine: Wine,
pub dxvk: Dxvk, pub dxvk: Dxvk,
pub enhancements: Enhancements, pub enhancements: Enhancements,
@ -33,10 +35,8 @@ pub struct Game {
impl Default for Game { impl Default for Game {
#[inline] #[inline]
fn default() -> Self { fn default() -> Self {
let launcher_dir = launcher_dir().expect("Failed to get launcher dir");
Self { Self {
path: launcher_dir.join(concat!("Hon", "kai Imp", "act")), path: Paths::default(),
wine: Wine::default(), wine: Wine::default(),
dxvk: Dxvk::default(), dxvk: Dxvk::default(),
enhancements: Enhancements::default(), enhancements: Enhancements::default(),
@ -51,28 +51,21 @@ impl From<&JsonValue> for Game {
let default = Self::default(); let default = Self::default();
Self { Self {
path: match value.get("path") { path: value.get("path")
Some(value) => match value.as_str() { .map(Paths::from)
Some(value) => PathBuf::from(value), .unwrap_or(default.path),
None => default.path
},
None => default.path
},
wine: match value.get("wine") { wine: value.get("wine")
Some(value) => Wine::from(value), .map(Wine::from)
None => default.wine .unwrap_or(default.wine),
},
dxvk: match value.get("dxvk") { dxvk: value.get("dxvk")
Some(value) => Dxvk::from(value), .map(Dxvk::from)
None => default.dxvk .unwrap_or(default.dxvk),
},
enhancements: match value.get("enhancements") { enhancements: value.get("enhancements")
Some(value) => Enhancements::from(value), .map(Enhancements::from)
None => default.enhancements .unwrap_or(default.enhancements),
},
environment: match value.get("environment") { environment: match value.get("environment") {
Some(value) => match value.as_object() { Some(value) => match value.as_object() {

View file

@ -0,0 +1,117 @@
use std::path::{Path, PathBuf};
use serde::{Serialize, Deserialize};
use serde_json::Value as JsonValue;
use anime_game_core::honkai::consts::GameEdition;
use crate::honkai::consts::launcher_dir;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Paths {
pub global: PathBuf,
pub sea: PathBuf,
pub china: PathBuf,
pub taiwan: PathBuf,
pub korea: PathBuf,
pub japan: PathBuf
}
impl Paths {
/// Get game path for given edition
pub fn for_edition(&self, edition: impl Into<GameEdition>) -> &Path {
match edition.into() {
GameEdition::Global => self.global.as_path(),
GameEdition::Sea => self.sea.as_path(),
GameEdition::China => self.china.as_path(),
GameEdition::Taiwan => self.taiwan.as_path(),
GameEdition::Korea => self.korea.as_path(),
GameEdition::Japan => self.japan.as_path()
}
}
}
impl Default for Paths {
fn default() -> Self {
let launcher_dir = launcher_dir().expect("Failed to get launcher dir");
Self {
global: launcher_dir.join(concat!("Hon", "kai Imp", "act")),
sea: launcher_dir.join(concat!("Hon", "kai Imp", "act Sea")),
china: launcher_dir.join(concat!("Hon", "kai Imp", "act China")),
taiwan: launcher_dir.join(concat!("Hon", "kai Imp", "act Taiwan")),
korea: launcher_dir.join(concat!("Hon", "kai Imp", "act Korea")),
japan: launcher_dir.join(concat!("Hon", "kai Imp", "act Japan")),
}
}
}
impl From<&JsonValue> for Paths {
fn from(value: &JsonValue) -> Self {
let default = Self::default();
// SDK 1.8.13 and earlier
if value.is_string() {
let path = PathBuf::from(value.as_str().unwrap());
Self {
sea: path.parent()
.map(|value| value.join(concat!("Hon", "kai Imp", "act Sea")))
.unwrap_or(default.sea),
china: path.parent()
.map(|value| value.join(concat!("Hon", "kai Imp", "act China")))
.unwrap_or(default.china),
taiwan: path.parent()
.map(|value| value.join(concat!("Hon", "kai Imp", "act Taiwan")))
.unwrap_or(default.taiwan),
korea: path.parent()
.map(|value| value.join(concat!("Hon", "kai Imp", "act Korea")))
.unwrap_or(default.korea),
japan: path.parent()
.map(|value| value.join(concat!("Hon", "kai Imp", "act Japan")))
.unwrap_or(default.japan),
global: path
}
}
// SDK 1.9.0 and later
else {
Self {
global: value.get("global")
.and_then(JsonValue::as_str)
.map(PathBuf::from)
.unwrap_or(default.global),
sea: value.get("sea")
.and_then(JsonValue::as_str)
.map(PathBuf::from)
.unwrap_or(default.sea),
china: value.get("china")
.and_then(JsonValue::as_str)
.map(PathBuf::from)
.unwrap_or(default.china),
taiwan: value.get("taiwan")
.and_then(JsonValue::as_str)
.map(PathBuf::from)
.unwrap_or(default.taiwan),
korea: value.get("korea")
.and_then(JsonValue::as_str)
.map(PathBuf::from)
.unwrap_or(default.korea),
japan: value.get("japan")
.and_then(JsonValue::as_str)
.map(PathBuf::from)
.unwrap_or(default.japan),
}
}
}
}

View file

@ -46,8 +46,9 @@ pub fn run() -> anyhow::Result<()> {
tracing::info!("Preparing to run the game"); tracing::info!("Preparing to run the game");
let config = Config::get()?; let config = Config::get()?;
let game_path = config.game.path.for_edition(config.launcher.edition).to_path_buf();
if !config.game.path.exists() { if !game_path.exists() {
return Err(anyhow::anyhow!("Game is not installed")); return Err(anyhow::anyhow!("Game is not installed"));
} }
@ -60,7 +61,7 @@ pub fn run() -> anyhow::Result<()> {
let mut folders = Folders { let mut folders = Folders {
wine: config.game.wine.builds.join(&wine.name), wine: config.game.wine.builds.join(&wine.name),
prefix: config.game.wine.prefix.clone(), prefix: config.game.wine.prefix.clone(),
game: config.game.path.clone(), game: game_path.clone(),
patch: config.patch.path.clone(), patch: config.patch.path.clone(),
temp: config.launcher.temp.clone().unwrap_or(std::env::temp_dir()) temp: config.launcher.temp.clone().unwrap_or(std::env::temp_dir())
}; };
@ -221,7 +222,7 @@ pub fn run() -> anyhow::Result<()> {
// We use real current dir here because sandboxed one // We use real current dir here because sandboxed one
// obviously doesn't exist // obviously doesn't exist
command.current_dir(&config.game.path) command.current_dir(game_path)
.spawn()?.wait_with_output()?; .spawn()?.wait_with_output()?;
#[cfg(feature = "discord-rpc")] #[cfg(feature = "discord-rpc")]

View file

@ -42,6 +42,7 @@ pub enum StateUpdating {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct LauncherStateParams<F: Fn(StateUpdating)> { pub struct LauncherStateParams<F: Fn(StateUpdating)> {
pub wine_prefix: PathBuf, pub wine_prefix: PathBuf,
pub game_path: PathBuf, pub game_path: PathBuf,
pub game_edition: GameEdition, pub game_edition: GameEdition,
@ -138,7 +139,8 @@ impl LauncherState {
Self::get(LauncherStateParams { Self::get(LauncherStateParams {
wine_prefix: config.get_wine_prefix_path(), wine_prefix: config.get_wine_prefix_path(),
game_path: config.game.path,
game_path: config.game.path.for_edition(config.launcher.edition).to_path_buf(),
game_edition: config.launcher.edition, game_edition: config.launcher.edition,
patch_folder: config.patch.path, patch_folder: config.patch.path,

View file

@ -16,25 +16,21 @@ impl From<&JsonValue> for Enhancements {
let default = Self::default(); let default = Self::default();
Self { Self {
fsr: match value.get("fsr") { fsr: value.get("fsr")
Some(value) => Fsr::from(value), .map(Fsr::from)
None => default.fsr .unwrap_or(default.fsr),
},
gamemode: match value.get("gamemode") { gamemode: value.get("gamemode")
Some(value) => value.as_bool().unwrap_or(default.gamemode), .and_then(JsonValue::as_bool)
None => default.gamemode .unwrap_or(default.gamemode),
},
hud: match value.get("hud") { hud: value.get("hud")
Some(value) => HUD::from(value), .map(HUD::from)
None => default.hud .unwrap_or(default.hud),
},
gamescope: match value.get("gamescope") { gamescope: value.get("gamescope")
Some(value) => Gamescope::from(value), .map(Gamescope::from)
None => default.gamescope .unwrap_or(default.gamescope)
}
} }
} }
} }

View file

@ -59,20 +59,17 @@ impl From<&JsonValue> for Game {
None => default.path None => default.path
}, },
wine: match value.get("wine") { wine: value.get("wine")
Some(value) => Wine::from(value), .map(Wine::from)
None => default.wine .unwrap_or(default.wine),
},
dxvk: match value.get("dxvk") { dxvk: value.get("dxvk")
Some(value) => Dxvk::from(value), .map(Dxvk::from)
None => default.dxvk .unwrap_or(default.dxvk),
},
enhancements: match value.get("enhancements") { enhancements: value.get("enhancements")
Some(value) => Enhancements::from(value), .map(Enhancements::from)
None => default.enhancements .unwrap_or(default.enhancements),
},
environment: match value.get("environment") { environment: match value.get("environment") {
Some(value) => match value.as_object() { Some(value) => match value.as_object() {

View file

@ -16,25 +16,21 @@ impl From<&JsonValue> for Enhancements {
let default = Self::default(); let default = Self::default();
Self { Self {
fsr: match value.get("fsr") { fsr: value.get("fsr")
Some(value) => Fsr::from(value), .map(Fsr::from)
None => default.fsr .unwrap_or(default.fsr),
},
gamemode: match value.get("gamemode") { gamemode: value.get("gamemode")
Some(value) => value.as_bool().unwrap_or(default.gamemode), .and_then(JsonValue::as_bool)
None => default.gamemode .unwrap_or(default.gamemode),
},
hud: match value.get("hud") { hud: value.get("hud")
Some(value) => HUD::from(value), .map(HUD::from)
None => default.hud .unwrap_or(default.hud),
},
gamescope: match value.get("gamescope") { gamescope: value.get("gamescope")
Some(value) => Gamescope::from(value), .map(Gamescope::from)
None => default.gamescope .unwrap_or(default.gamescope)
}
} }
} }
} }

View file

@ -52,25 +52,21 @@ impl From<&JsonValue> for Game {
let default = Self::default(); let default = Self::default();
Self { Self {
path: match value.get("path") { path: value.get("path")
Some(value) => Paths::from(value), .map(Paths::from)
None => default.path .unwrap_or(default.path),
},
wine: match value.get("wine") { wine: value.get("wine")
Some(value) => Wine::from(value), .map(Wine::from)
None => default.wine .unwrap_or(default.wine),
},
dxvk: match value.get("dxvk") { dxvk: value.get("dxvk")
Some(value) => Dxvk::from(value), .map(Dxvk::from)
None => default.dxvk .unwrap_or(default.dxvk),
},
enhancements: match value.get("enhancements") { enhancements: value.get("enhancements")
Some(value) => Enhancements::from(value), .map(Enhancements::from)
None => default.enhancements .unwrap_or(default.enhancements),
},
environment: match value.get("environment") { environment: match value.get("environment") {
Some(value) => match value.as_object() { Some(value) => match value.as_object() {

View file

@ -19,7 +19,7 @@ impl Paths {
pub fn for_edition(&self, edition: impl Into<GameEdition>) -> &Path { pub fn for_edition(&self, edition: impl Into<GameEdition>) -> &Path {
match edition.into() { match edition.into() {
GameEdition::Global => self.global.as_path(), GameEdition::Global => self.global.as_path(),
GameEdition::China => self.china.as_path() GameEdition::China => self.china.as_path()
} }
} }
} }
@ -30,7 +30,7 @@ impl Default for Paths {
Self { Self {
global: launcher_dir.join("HSR"), global: launcher_dir.join("HSR"),
china: launcher_dir.join("HSR China") china: launcher_dir.join("HSR China")
} }
} }
} }