From 62edcdae0866382368a04d61e304329e7a95c4cd Mon Sep 17 00:00:00 2001 From: akanyan Date: Fri, 14 Mar 2025 15:16:49 +0100 Subject: [PATCH] fix: restore wine configuration --- README.md | 2 +- rust/capabilities/default.json | 4 +- rust/src/lib.rs | 2 +- rust/src/model/config.rs | 47 ++++++++++++++++++- .../{display.rs => display_windows.rs} | 15 ------ rust/src/modules/mod.rs | 6 ++- rust/src/modules/network.rs | 21 ++++++--- rust/src/modules/segatools.rs | 16 ------- rust/src/profiles/mod.rs | 5 +- rust/src/profiles/ongeki.rs | 33 ++++++------- rust/src/util.rs | 8 ++-- rust/tauri.conf.json | 4 +- src/components/OptionList.vue | 6 ++- 13 files changed, 97 insertions(+), 72 deletions(-) rename rust/src/modules/{display.rs => display_windows.rs} (91%) diff --git a/README.md b/README.md index 2f01b31..18ef624 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ bun run tauri build Once a profile is set up, it is possible to bypass the GUI: ```sh -startliner --start --game ongeki --name profile-name +startliner --start --game ongeki --profile ``` ### Package format diff --git a/rust/capabilities/default.json b/rust/capabilities/default.json index e4502f7..75802b3 100644 --- a/rust/capabilities/default.json +++ b/rust/capabilities/default.json @@ -13,6 +13,8 @@ "deep-link:default", "fs:default", "fs:allow-data-read-recursive", - "fs:allow-data-write-recursive" + "fs:allow-data-write-recursive", + "fs:allow-config-read-recursive", + "fs:allow-config-write-recursive" ] } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index ae4ce97..aa435d2 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -57,7 +57,7 @@ pub async fn run(_args: Vec) { if let Ok(matches) = app.cli().matches() { let start_arg = matches.args.get("start").expect("Invalid argument configuration"); let game_arg = matches.args.get("game").expect("Invalid argument configuration"); - let name_arg = matches.args.get("name").expect("Invalid argument configuration"); + let name_arg = matches.args.get("profile").expect("Invalid argument configuration"); log::debug!("{:?} {:?} {:?}", start_arg, game_arg, name_arg); if start_arg.occurrences > 0 { start_immediately = true; diff --git a/rust/src/model/config.rs b/rust/src/model/config.rs index d050883..28b6ee5 100644 --- a/rust/src/model/config.rs +++ b/rust/src/model/config.rs @@ -11,6 +11,19 @@ pub struct Segatools { pub intel: bool, } +impl Default for Segatools { + fn default() -> Self { + Segatools { + target: PathBuf::default(), + amfs: PathBuf::default(), + option: PathBuf::default(), + appdata: PathBuf::from("appdata"), + enable_aime: false, + intel: false + } + } +} + #[derive(Deserialize, Serialize, Clone, Default, PartialEq)] pub enum DisplayMode { Window, @@ -28,6 +41,19 @@ pub struct Display { pub borderless_fullscreen: bool, } +impl Default for Display { + fn default() -> Self { + Display { + target: "default".to_owned(), + rez: (1080, 1920), + mode: DisplayMode::Borderless, + rotation: 0, + frequency: 60, + borderless_fullscreen: true, + } + } +} + #[derive(Deserialize, Serialize, Clone, Default, PartialEq)] pub enum NetworkType { #[default] Remote, @@ -38,7 +64,7 @@ pub enum NetworkType { pub struct Network { pub network_type: NetworkType, - pub local_path: String, + pub local_path: PathBuf, pub local_console: bool, pub remote_address: String, @@ -50,5 +76,22 @@ pub struct Network { #[derive(Deserialize, Serialize, Clone, Default)] pub struct BepInEx { - pub console: bool + pub console: bool, +} + +#[derive(Deserialize, Serialize, Clone)] +pub struct Wine { + pub runtime: PathBuf, + pub prefix: PathBuf, +} + +impl Default for Wine { + fn default() -> Self { + Wine { + runtime: PathBuf::from("/usr/bin/wine"), + prefix: std::env::var("HOME") + .and_then(|home| Ok(PathBuf::from(home).join(".wine"))) + .unwrap_or_default() + } + } } \ No newline at end of file diff --git a/rust/src/modules/display.rs b/rust/src/modules/display_windows.rs similarity index 91% rename from rust/src/modules/display.rs rename to rust/src/modules/display_windows.rs index 1efbc41..82c6c79 100644 --- a/rust/src/modules/display.rs +++ b/rust/src/modules/display_windows.rs @@ -4,7 +4,6 @@ use anyhow::Result; use displayz::{query_displays, DisplaySet}; use tauri::{AppHandle, Listener}; -#[cfg(target_os = "windows")] #[derive(Clone)] pub struct DisplayInfo { pub primary: String, @@ -20,20 +19,6 @@ impl Default for DisplayInfo { } } -impl Default for Display { - fn default() -> Self { - Display { - target: "default".to_owned(), - rez: (1080, 1920), - mode: DisplayMode::Borderless, - rotation: 0, - frequency: 60, - borderless_fullscreen: true, - } - } -} - -#[cfg(target_os = "windows")] impl Display { pub fn activate(&self, app: AppHandle) { let display = self.clone(); diff --git a/rust/src/modules/mod.rs b/rust/src/modules/mod.rs index 876e176..9291840 100644 --- a/rust/src/modules/mod.rs +++ b/rust/src/modules/mod.rs @@ -1,5 +1,7 @@ -pub mod display; pub mod package; pub mod segatools; pub mod network; -pub mod bepinex; \ No newline at end of file +pub mod bepinex; + +#[cfg(target_os = "windows")] +pub mod display_windows; \ No newline at end of file diff --git a/rust/src/modules/network.rs b/rust/src/modules/network.rs index 3436118..1b4ab9a 100644 --- a/rust/src/modules/network.rs +++ b/rust/src/modules/network.rs @@ -27,7 +27,7 @@ impl Network { if self.network_type == NetworkType::Artemis { let network_path = PathBuf::from(&self.local_path); let artemis_dir = network_path.parent() - .ok_or_else(|| anyhow!("Invalid ARTEMiS path {}", &self.local_path))?; + .ok_or_else(|| anyhow!("Invalid ARTEMiS path {:?}", &self.local_path))?; let cfg_path = artemis_dir.join("config").join("core.yaml"); let cfg = std::fs::read_to_string(&cfg_path) @@ -41,15 +41,22 @@ impl Network { if let Some(hostname) = hostname { ini.with_section(Some("dns")).set("default", hostname); - #[cfg(target_os = "windows")] - let mut cmd = Command::new("cmd.exe"); - cmd.arg("/C"); + let mut cmd: Command; - if self.local_console == true { - cmd.arg("start"); + if cfg!(target_os = "windows") { + cmd = Command::new("cmd.exe"); + cmd.arg("/C"); + + if self.local_console == true { + cmd.arg("start"); + } + } else { + cmd = Command::new("sh"); } - cmd.args(["python", &self.local_path]); + + cmd.arg("python"); + cmd.arg(&self.local_path); cmd.current_dir(artemis_dir); cmd.spawn() .map_err(|e| anyhow!("Unable to spawn artemis: {}", e))?; diff --git a/rust/src/modules/segatools.rs b/rust/src/modules/segatools.rs index 8e17493..e3ee79f 100644 --- a/rust/src/modules/segatools.rs +++ b/rust/src/modules/segatools.rs @@ -1,23 +1,7 @@ - -use std::path::PathBuf; - use anyhow::{anyhow, Result}; use ini::Ini; use crate::{model::{config::Segatools, segatools_base::segatools_base}, profiles::ProfilePaths, util::{self, PathStr}}; -impl Default for Segatools { - fn default() -> Self { - Segatools { - target: PathBuf::default(), - amfs: PathBuf::default(), - option: PathBuf::default(), - appdata: PathBuf::from("appdata"), - enable_aime: false, - intel: false - } - } -} - impl Segatools { pub async fn line_up(&self, p: &impl ProfilePaths) -> Result { log::debug!("begin line-up: segatools"); diff --git a/rust/src/profiles/mod.rs b/rust/src/profiles/mod.rs index a200e23..ac8b9c7 100644 --- a/rust/src/profiles/mod.rs +++ b/rust/src/profiles/mod.rs @@ -70,7 +70,7 @@ impl AnyProfile { Self::OngekiProfile(p) => &mut p.mods } } - pub async fn line_up(&self, app: AppHandle, pkg_hash: String) -> Result<()> { + pub async fn line_up(&self, _app: AppHandle, pkg_hash: String) -> Result<()> { match self { Self::OngekiProfile(p) => { if !p.data_dir().exists() { @@ -80,7 +80,8 @@ impl AnyProfile { let hash_path = p.data_dir().join(".sl-state"); let meta = self.meta(); - p.display.activate(app.clone()); + #[cfg(target_os = "windows")] + p.display.activate(_app.clone()); util::clean_up_opts(p.data_dir().join("option"))?; diff --git a/rust/src/profiles/ongeki.rs b/rust/src/profiles/ongeki.rs index 0286228..e56ad96 100644 --- a/rust/src/profiles/ongeki.rs +++ b/rust/src/profiles/ongeki.rs @@ -4,7 +4,6 @@ use tauri::Emitter; use std::{collections::BTreeSet, path::PathBuf, process::Stdio}; use crate::model::config::BepInEx; use crate::profiles::fixed_name; -use crate::util::PathStr; use crate::{model::{config::{Display, DisplayMode, Network, Segatools}, misc::Game, segatools_base::segatools_base}, pkg::PkgKey, util}; use super::{Profile, ProfileMeta, ProfilePaths}; use anyhow::{anyhow, Result}; @@ -23,7 +22,10 @@ pub struct OngekiProfile { pub sgt: Segatools, pub display: Display, pub network: Network, - pub bepinex: BepInEx + pub bepinex: BepInEx, + + #[cfg(not(target_os = "windows"))] + pub wine: crate::model::config::Wine, } impl Profile for OngekiProfile { @@ -36,7 +38,9 @@ impl Profile for OngekiProfile { sgt: Segatools::default(), display: Display::default(), network: Network::default(), - bepinex: BepInEx::default() + bepinex: BepInEx::default(), + #[cfg(not(target_os = "windows"))] + wine: crate::model::config::Wine::default(), }; p.save()?; std::fs::write(p.config_dir().join("segatools-base.ini"), segatools_base())?; @@ -92,11 +96,8 @@ impl Profile for OngekiProfile { } #[cfg(target_os = "linux")] { - let wine = p.data.wine_runtime.clone() - .unwrap_or_else(|| std::path::PathBuf::from("/usr/bin/wine")); - - game_builder = Command::new(&wine); - amd_builder = Command::new(&wine); + game_builder = Command::new(&self.wine.runtime); + amd_builder = Command::new(&self.wine.runtime); game_builder.arg(exe_dir.join("inject.exe")); amd_builder.arg("cmd.exe"); @@ -107,9 +108,10 @@ impl Profile for OngekiProfile { &ini_path, ) .current_dir(&exe_dir) + .arg("/C") + .arg(&exe_dir.join("inject.exe")) .args([ - "/C", - &exe_dir.join("inject.exe").stringify()?, "-d", "-k", "mu3hook.dll", + "-d", "-k", "mu3hook.dll", "amdaemon.exe", "-f", "-c", "config_common.json", "config_server.json", "config_client.json" ]); game_builder @@ -136,17 +138,10 @@ impl Profile for OngekiProfile { #[cfg(target_os = "linux")] { - let wineprefix = p.data.wine_prefix.clone().unwrap_or_else(|| - directories::UserDirs::new() - .expect("No home directory") - .home_dir() - .join(".wine") - ); - amd_builder.env("WINEPREFIX", &wineprefix); - game_builder.env("WINEPREFIX", &wineprefix); + amd_builder.env("WINEPREFIX", &self.wine.prefix); + game_builder.env("WINEPREFIX", &self.wine.prefix); } - let amd_log = File::create(self.data_dir().join("amdaemon.log"))?; let game_log = File::create(self.data_dir().join("mu3.log"))?; diff --git a/rust/src/util.rs b/rust/src/util.rs index 75688c0..f3cf2c9 100644 --- a/rust/src/util.rs +++ b/rust/src/util.rs @@ -1,6 +1,7 @@ use anyhow::{anyhow, Result}; use serde::{Deserialize, Serialize}; use tauri::{AppHandle, Manager}; +use tokio::process::Command; use std::{path::{Path, PathBuf}, sync::OnceLock}; use crate::model::misc::Game; @@ -86,7 +87,7 @@ pub fn copy_directory(src: impl AsRef, dst: impl AsRef, recursive: b #[cfg(target_os = "linux")] pub async fn symlink(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - fs::symlink(src, dst).await + tokio::fs::symlink(src, dst).await } #[cfg(target_os = "windows")] @@ -100,8 +101,6 @@ pub static CREATE_NO_WINDOW: u32 = 0x08000000; #[cfg(target_os = "windows")] pub async fn pkill(process_name: &str) { - use tokio::process::Command; - _ = Command::new("taskkill.exe").arg("/f").arg("/im").arg(process_name) .creation_flags(CREATE_NO_WINDOW).output().await; } @@ -120,7 +119,10 @@ pub fn clean_up_opts(dir: impl AsRef) -> Result<()> { let path = entry.path(); log::debug!("{:?}", path); if path.is_symlink() { + #[cfg(target_os = "windows")] std::fs::remove_dir(path)?; + #[cfg(not(target_os = "windows"))] + std::fs::remove_file(path)?; } else { log::error!("Not a symlink: {:?}", path); } diff --git a/rust/tauri.conf.json b/rust/tauri.conf.json index 98ff5fd..3f30953 100644 --- a/rust/tauri.conf.json +++ b/rust/tauri.conf.json @@ -34,8 +34,8 @@ "possibleValues": ["chunithm", "ongeki"] }, { - "short": "n", - "name": "name", + "short": "p", + "name": "profile", "takesValue": true, "description": "Profile name" } diff --git a/src/components/OptionList.vue b/src/components/OptionList.vue index a7a6edb..a362d30 100644 --- a/src/components/OptionList.vue +++ b/src/components/OptionList.vue @@ -181,7 +181,11 @@ const extraDisplayOptionsDisabled = computed(() => { :disabled="extraDisplayOptionsDisabled" /> - +