- improved wine/dxvk features,
  added command used to run the game
This commit is contained in:
Observer KRypt0n_ 2023-03-08 18:36:01 +02:00
parent d64d15cf27
commit ba11109082
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
5 changed files with 109 additions and 29 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "anime-launcher-sdk"
version = "0.4.0"
version = "0.5.0"
authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"]
license = "GPL-3.0"
readme = "README.md"

View file

@ -34,6 +34,14 @@ impl Group {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Features {
/// Standard environment variables that are applied when you launch the game
///
/// Available keywords:
/// - `%build%` - path to wine build
/// - `%prefix%` - path to wine prefix
/// - `%temp%` - path to temp folder specified in config file
/// - `%launcher%` - path to launcher folder
/// - `%game%` - path to the game
pub env: HashMap<String, String>
}
@ -70,11 +78,12 @@ impl From<&JsonValue> for Features {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Version {
pub name: String,
pub version: String,
pub uri: String
pub uri: String,
pub features: Option<Features>
}
impl Version {

View file

@ -36,6 +36,11 @@ pub fn get_wine_versions(index: &Path) -> anyhow::Result<Vec<wine::Group>> {
None => anyhow::bail!("Wrong components index structure: wine group's title not found")
};
let features = match group.get("features") {
Some(features) => features.into(),
None => wine::Features::default()
};
let versions = serde_json::from_str::<serde_json::Value>(&std::fs::read_to_string(index.join("wine").join(format!("{name}.json")))?)?;
let mut wine_versions = Vec::new();
@ -43,18 +48,19 @@ pub fn get_wine_versions(index: &Path) -> anyhow::Result<Vec<wine::Group>> {
match versions.as_array() {
Some(versions) => {
for version in versions {
wine_versions.push(serde_json::from_value::<wine::Version>(version.to_owned())?);
wine_versions.push(wine::Version {
name: version["name"].as_str().unwrap().to_string(),
title: version["title"].as_str().unwrap().to_string(),
uri: version["uri"].as_str().unwrap().to_string(),
files: serde_json::from_value::<wine::Files>(version["files"].to_owned())?,
features: version.get("features").map(|v| v.into())
});
}
}
None => anyhow::bail!("Wrong components index structure: wine versions must be a list")
}
let features = match group.get("features") {
Some(features) => features.into(),
None => wine::Features::default()
};
wine_groups.push(wine::Group {
name,
title,
@ -112,7 +118,12 @@ pub fn get_dxvk_versions(index: &Path) -> anyhow::Result<Vec<dxvk::Group>> {
match versions.as_array() {
Some(versions) => {
for version in versions {
dxvk_versions.push(serde_json::from_value::<dxvk::Version>(version.to_owned())?);
dxvk_versions.push(dxvk::Version {
name: version["name"].as_str().unwrap().to_string(),
version: version["version"].as_str().unwrap().to_string(),
uri: version["uri"].as_str().unwrap().to_string(),
features: version.get("features").map(|v| v.into())
});
}
}

View file

@ -34,7 +34,27 @@ impl Group {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Features {
/// Whether this wine group needs DXVK
pub need_dxvk: bool,
/// Command used to launch the game
///
/// Available keywords:
/// - `%build%` - path to wine build
/// - `%prefix%` - path to wine prefix
/// - `%temp%` - path to temp folder specified in config file
/// - `%launcher%` - path to launcher folder
/// - `%game%` - path to the game
pub command: Option<String>,
/// Standard environment variables that are applied when you launch the game
///
/// Available keywords:
/// - `%build%` - path to wine build
/// - `%prefix%` - path to wine prefix
/// - `%temp%` - path to temp folder specified in config file
/// - `%launcher%` - path to launcher folder
/// - `%game%` - path to the game
pub env: HashMap<String, String>
}
@ -42,6 +62,7 @@ impl Default for Features {
fn default() -> Self {
Self {
need_dxvk: true,
command: None,
env: HashMap::new()
}
}
@ -57,6 +78,11 @@ impl From<&JsonValue> for Features {
None => default.need_dxvk
},
command: match value.get("command") {
Some(value) => value.as_str().map(|value| value.to_string()),
None => default.command
},
env: match value.get("env") {
Some(value) => {
if let Some(object) = value.as_object() {
@ -77,21 +103,13 @@ impl From<&JsonValue> for Features {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Version {
pub name: String,
pub title: String,
pub uri: String,
pub files: Files
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Files {
pub wine: String,
pub wine64: Option<String>,
pub wineserver: Option<String>,
pub wineboot: Option<String>,
pub winecfg: Option<String>
pub files: Files,
pub features: Option<Features>
}
impl Version {
@ -158,6 +176,15 @@ impl Version {
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Files {
pub wine: String,
pub wine64: Option<String>,
pub wineserver: Option<String>,
pub wineboot: Option<String>,
pub winecfg: Option<String>
}
pub fn get_groups<T: Into<PathBuf>>(components: T) -> anyhow::Result<Vec<Group>> {
ComponentsLoader::new(components).get_wine_versions()
}

View file

@ -1,4 +1,5 @@
use std::process::{Command, Stdio};
use std::path::PathBuf;
use anime_game_core::genshin::telemetry;
@ -11,6 +12,17 @@ use super::fps_unlocker::FpsUnlocker;
#[cfg(feature = "discord-rpc")]
use super::discord_rpc::*;
fn replace_keywords<T: ToString>(command: T, config: &config::Config) -> String {
let wine_build = config.game.wine.builds.join(config.game.wine.selected.as_ref().unwrap());
command.to_string()
.replace("%build%", &wine_build.to_string_lossy())
.replace("%prefix%", &config.game.wine.prefix.to_string_lossy())
.replace("%temp%", &config.launcher.temp.as_ref().unwrap_or(&PathBuf::from("/tmp")).to_string_lossy())
.replace("%launcher%", &consts::launcher_dir().unwrap().to_string_lossy())
.replace("%game%", &config.game.path.to_string_lossy())
}
/// Try to run the game
///
/// This function will freeze thread it was called from while the game is running
@ -28,6 +40,14 @@ pub fn run() -> anyhow::Result<()> {
anyhow::bail!("Couldn't find wine executable");
};
let features = match wine.features {
Some(features) => features,
None => match wine.find_group(&config.components.path)? {
Some(group) => group.features,
None => anyhow::bail!("Couldn't find wine group")
}
};
// Check telemetry servers
tracing::info!("Checking telemetry");
@ -86,7 +106,14 @@ pub fn run() -> anyhow::Result<()> {
bash_chain += "gamemoderun ";
}
bash_chain += &format!("'{}' ", config.game.wine.builds.join(wine.name).join(wine.files.wine64.unwrap_or(wine.files.wine)).to_string_lossy());
let wine_build = config.game.wine.builds.join(&wine.name);
let run_command = features.command
.map(|command| replace_keywords(command, &config))
.unwrap_or(format!("'{}'", wine_build.join(wine.files.wine64.unwrap_or(wine.files.wine)).to_string_lossy()));
bash_chain += &run_command;
bash_chain += " ";
if let Some(virtual_desktop) = config.game.wine.virtual_desktop.get_command() {
bash_chain += &format!("{virtual_desktop} ");
@ -113,7 +140,7 @@ pub fn run() -> anyhow::Result<()> {
}
let bash_chain = match &config.game.command {
Some(command) => command.replace("%command%", &bash_chain),
Some(command) => replace_keywords(command, &config).replace("%command%", &bash_chain),
None => bash_chain
};
@ -128,16 +155,22 @@ pub fn run() -> anyhow::Result<()> {
command.env("WINEPREFIX", &config.game.wine.prefix);
// Add environment flags for selected wine
if let Ok(Some(wine )) = config.get_selected_wine() {
if let Ok(Some(group)) = wine.find_group(&config.components.path) {
command.envs(group.features.env);
}
for (key, value) in features.env.into_iter() {
command.env(key, replace_keywords(value, &config));
}
// Add environment flags for selected dxvk
if let Ok(Some(dxvk )) = config.get_selected_dxvk() {
if let Ok(Some(group)) = dxvk.find_group(&config.components.path) {
command.envs(group.features.env);
if let Some(features) = &dxvk.features {
for (key, value) in features.env.iter() {
command.env(key, replace_keywords(value, &config));
}
}
else if let Ok(Some(group)) = dxvk.find_group(&config.components.path) {
for (key, value) in group.features.env.into_iter() {
command.env(key, replace_keywords(value, &config));
}
}
}