From 13a56f4200775d12d807b6c19f7acfb093525a21 Mon Sep 17 00:00:00 2001 From: Ap_Tx <3045929398@qq.com> Date: Sat, 17 Oct 2026 16:12:28 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20Linux=20=E7=B3=BB=E7=BB=9F=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E6=97=B6=E6=B8=B8=E6=88=8F=E7=9B=AE=E5=BD=95=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E5=9B=9E=E9=80=80=E5=88=B0=E7=94=A8=E6=88=B7=E4=B8=BB?= =?UTF-8?q?=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 从 deb 等系统包安装时,启动器可执行文件位于 /usr/bin,此前一键安装 StarLight 实例的"选择游戏目录"弹窗会默认到这个系统目录,普通用户既 无写权限,也不适合存放游戏数据。 将默认目录计算移入 theseus::default_game_dir_root():Linux 下若可执行 文件位于 /usr、/opt、/snap 等系统路径,回退到用户主目录;便携版与其 他平台仍使用可执行文件所在目录。 --- apps/app/src/main.rs | 7 ++----- packages/app-lib/src/lib.rs | 2 +- packages/app-lib/src/util/platform.rs | 29 +++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/apps/app/src/main.rs b/apps/app/src/main.rs index cfd1486..5e343d9 100644 --- a/apps/app/src/main.rs +++ b/apps/app/src/main.rs @@ -324,12 +324,9 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> { /// external game-directory root for the one-click StarLight install flow. #[tauri::command] fn get_launcher_root_dir() -> api::Result { - let exe = std::env::current_exe().map_err(|error| { - theseus::Error::from(theseus::ErrorKind::FSError(error.to_string())) - })?; - let dir = exe.parent().ok_or_else(|| { + let dir = theseus::default_game_dir_root().ok_or_else(|| { theseus::Error::from(theseus::ErrorKind::FSError( - "Launcher executable has no parent directory".to_string(), + "Could not determine a default game directory root".to_string(), )) })?; Ok(dir.to_string_lossy().into_owned()) diff --git a/packages/app-lib/src/lib.rs b/packages/app-lib/src/lib.rs index b557d3b..f94cf3d 100644 --- a/packages/app-lib/src/lib.rs +++ b/packages/app-lib/src/lib.rs @@ -39,7 +39,7 @@ pub use state::{DirectoryInfo, State}; pub use storage::*; pub use util::fetch::build_proxied_client; pub use util::file_lock::{LockingProcess, get_locking_processes}; -pub use util::platform::is_process_elevated; +pub use util::platform::{default_game_dir_root, is_process_elevated}; pub use util::proxy::{ProxyConfig, ProxyMode, ProxyTestResult}; pub use util::symlink::SymlinkCapability; diff --git a/packages/app-lib/src/util/platform.rs b/packages/app-lib/src/util/platform.rs index 1c381b4..0003cd8 100644 --- a/packages/app-lib/src/util/platform.rs +++ b/packages/app-lib/src/util/platform.rs @@ -1,5 +1,6 @@ //! Platform-related code use daedalus::minecraft::{Os, OsRule}; +use std::path::PathBuf; /// (e.g. "Run as administrator" on Windows). #[cfg(target_os = "windows")] @@ -143,3 +144,31 @@ pub fn classpath_separator(java_arch: &str) -> &'static str { Os::Windows | Os::WindowsArm64 => ";", } } + +/// Root directory used as the default for one-click StarLight instance +/// installs. Portable builds live next to their executable, which is a fine +/// place for game data. System installs (e.g. a Linux `.deb` under `/usr/bin`) +/// do not, so fall back to the user's home directory there. +pub fn default_game_dir_root() -> Option { + let exe_dir = std::env::current_exe().ok()?.parent()?.to_path_buf(); + if cfg!(target_os = "linux") && is_system_install_dir(&exe_dir) { + return dirs::home_dir(); + } + Some(exe_dir) +} + +#[cfg(target_os = "linux")] +fn is_system_install_dir(path: &std::path::Path) -> bool { + const SYSTEM_PREFIXES: &[&str] = &[ + "/usr/", "/opt/", "/snap/", "/bin/", "/sbin/", "/lib/", "/lib64/", + ]; + let display = path.to_string_lossy(); + SYSTEM_PREFIXES + .iter() + .any(|prefix| display.starts_with(prefix)) +} + +#[cfg(not(target_os = "linux"))] +fn is_system_install_dir(_path: &std::path::Path) -> bool { + false +}