Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d17a66e44f | ||
|
|
871b0ee001 | ||
|
|
adebde714d | ||
|
|
13a56f4200 | ||
|
|
8b94e7dbbe |
No files matched your search
@@ -32,6 +32,31 @@ export const ANNOUNCEMENT_CHANGE_TYPES: readonly AnnouncementChangeType[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const launcherAnnouncements: readonly LauncherAnnouncement[] = [
|
export const launcherAnnouncements: readonly LauncherAnnouncement[] = [
|
||||||
|
{
|
||||||
|
id: 'launcher-1.0.2-beta7',
|
||||||
|
version: '1.0.2-beta7',
|
||||||
|
publishedAt: '2026-10-17',
|
||||||
|
title: {
|
||||||
|
'en-US': 'Starlight Launcher 1.0.2-beta7',
|
||||||
|
'zh-CN': 'Starlight Launcher 1.0.2-beta7',
|
||||||
|
},
|
||||||
|
changes: {
|
||||||
|
fixed: [
|
||||||
|
{
|
||||||
|
'en-US': 'Fixed real-time log backlog that could stall the console under heavy output.',
|
||||||
|
'zh-CN': '修复实时日志积压导致控制台卡顿的问题。',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'en-US': 'The update channel now defaults to the build type: installing a Beta build starts on the Beta channel instead of Release.',
|
||||||
|
'zh-CN': '更新通道默认值改为跟随安装包版本:安装 Beta 版后默认使用 Beta 通道,不再回落为 Release。',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'en-US': 'On Linux, the default game directory for StarLight instances no longer points at the system install path (e.g. /usr/bin); it falls back to the home directory.',
|
||||||
|
'zh-CN': 'Linux 上 StarLight 实例的默认游戏目录不再指向系统安装路径(如 /usr/bin),改为回退到用户主目录。',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'launcher-1.0.2-beta6',
|
id: 'launcher-1.0.2-beta6',
|
||||||
version: '1.0.2-beta6',
|
version: '1.0.2-beta6',
|
||||||
|
|||||||
@@ -324,12 +324,9 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
|||||||
/// external game-directory root for the one-click StarLight install flow.
|
/// external game-directory root for the one-click StarLight install flow.
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn get_launcher_root_dir() -> api::Result<String> {
|
fn get_launcher_root_dir() -> api::Result<String> {
|
||||||
let exe = std::env::current_exe().map_err(|error| {
|
let dir = theseus::default_game_dir_root().ok_or_else(|| {
|
||||||
theseus::Error::from(theseus::ErrorKind::FSError(error.to_string()))
|
|
||||||
})?;
|
|
||||||
let dir = exe.parent().ok_or_else(|| {
|
|
||||||
theseus::Error::from(theseus::ErrorKind::FSError(
|
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())
|
Ok(dir.to_string_lossy().into_owned())
|
||||||
@@ -339,7 +336,7 @@ fn get_launcher_root_dir() -> api::Result<String> {
|
|||||||
fn get_update_channel(app: tauri::AppHandle) -> api::Result<String> {
|
fn get_update_channel(app: tauri::AppHandle) -> api::Result<String> {
|
||||||
let channel = read_update_channel_state(&app)?
|
let channel = read_update_channel_state(&app)?
|
||||||
.active_channel
|
.active_channel
|
||||||
.unwrap_or_else(|| "release".to_string());
|
.unwrap_or_else(|| theseus::default_update_channel().to_string());
|
||||||
|
|
||||||
match channel.as_str() {
|
match channel.as_str() {
|
||||||
"release" | "beta" => Ok(channel),
|
"release" | "beta" => Ok(channel),
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ pub use logger::start_logger;
|
|||||||
pub use state::db::{
|
pub use state::db::{
|
||||||
backup_current_app_db_for_update, beta_database_exists,
|
backup_current_app_db_for_update, beta_database_exists,
|
||||||
copy_database_between_channels, copy_release_database_to_beta,
|
copy_database_between_channels, copy_release_database_to_beta,
|
||||||
current_app_database_path,
|
current_app_database_path, default_update_channel,
|
||||||
};
|
};
|
||||||
pub use state::{DirectoryInfo, State};
|
pub use state::{DirectoryInfo, State};
|
||||||
pub use storage::*;
|
pub use storage::*;
|
||||||
pub use util::fetch::build_proxied_client;
|
pub use util::fetch::build_proxied_client;
|
||||||
pub use util::file_lock::{LockingProcess, get_locking_processes};
|
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::proxy::{ProxyConfig, ProxyMode, ProxyTestResult};
|
||||||
pub use util::symlink::SymlinkCapability;
|
pub use util::symlink::SymlinkCapability;
|
||||||
|
|
||||||
|
|||||||
@@ -304,6 +304,18 @@ async fn app_db_path(settings_dir: &Path) -> crate::Result<PathBuf> {
|
|||||||
Ok(settings_dir.join(channel).join(LEGACY_APP_DB_FILE))
|
Ok(settings_dir.join(channel).join(LEGACY_APP_DB_FILE))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The update channel a fresh install should default to. Beta builds carry a
|
||||||
|
/// pre-release version (e.g. `1.0.2-beta7`), so their installers should start
|
||||||
|
/// on the Beta channel instead of silently falling back to Release.
|
||||||
|
pub fn default_update_channel() -> &'static str {
|
||||||
|
let version = env!("CARGO_PKG_VERSION");
|
||||||
|
if version.contains('-') {
|
||||||
|
"beta"
|
||||||
|
} else {
|
||||||
|
"release"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn read_update_channel(
|
async fn read_update_channel(
|
||||||
settings_dir: &Path,
|
settings_dir: &Path,
|
||||||
) -> crate::Result<&'static str> {
|
) -> crate::Result<&'static str> {
|
||||||
@@ -311,7 +323,7 @@ async fn read_update_channel(
|
|||||||
let contents = match tokio::fs::read_to_string(&path).await {
|
let contents = match tokio::fs::read_to_string(&path).await {
|
||||||
Ok(contents) => contents,
|
Ok(contents) => contents,
|
||||||
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
|
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
|
||||||
return Ok("release");
|
return Ok(default_update_channel());
|
||||||
}
|
}
|
||||||
Err(error) => return Err(error.into()),
|
Err(error) => return Err(error.into()),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//! Platform-related code
|
//! Platform-related code
|
||||||
use daedalus::minecraft::{Os, OsRule};
|
use daedalus::minecraft::{Os, OsRule};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
/// (e.g. "Run as administrator" on Windows).
|
/// (e.g. "Run as administrator" on Windows).
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
@@ -143,3 +144,31 @@ pub fn classpath_separator(java_arch: &str) -> &'static str {
|
|||||||
Os::Windows | Os::WindowsArm64 => ";",
|
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<PathBuf> {
|
||||||
|
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
|
||||||
|
}
|
||||||
Reference in new issue
Block a user