diff --git a/apps/oneclient/desktop/src/api/commands.rs b/apps/oneclient/desktop/src/api/commands.rs index 8a0ab057..cbcf55ee 100644 --- a/apps/oneclient/desktop/src/api/commands.rs +++ b/apps/oneclient/desktop/src/api/commands.rs @@ -162,7 +162,8 @@ impl OneClientApi for OneClientApiImpl { .ok_or_else(|| anyhow::anyhow!("cluster with id {} not found", cluster_id))?; match package { - ModpackFileKind::Managed((pkg, version)) => { + ModpackFileKind::Managed(box_) => { + let (pkg, version) = *box_; let model = api::packages::download_package(&pkg, &version, None, None).await?; api::packages::link_package(&model, &cluster, skip_compatibility).await?; api::packages::bundle_dao::track_bundle_package( diff --git a/apps/oneclient/desktop/src/constants.rs b/apps/oneclient/desktop/src/constants.rs index b12c79c8..71782903 100644 --- a/apps/oneclient/desktop/src/constants.rs +++ b/apps/oneclient/desktop/src/constants.rs @@ -1,9 +1,8 @@ // === API === -pub const CURSEFORGE_API_KEY: &'static str = - "$2a$10$6utA1UNSmFPrE/Lh7b7ndeeGmiOkjKNY8kpFB0fsmE/d42ZAfFgCe"; -pub const DISCORD_CLIENT_ID: &'static str = "1426999264633946334"; +pub const CURSEFORGE_API_KEY: &str = "$2a$10$6utA1UNSmFPrE/Lh7b7ndeeGmiOkjKNY8kpFB0fsmE/d42ZAfFgCe"; +pub const DISCORD_CLIENT_ID: &str = "1426999264633946334"; // === Meta === // Cannot contain trailing slash -pub const META_URL_BASE: &'static str = +pub const META_URL_BASE: &str = "https://raw.githubusercontent.com/Polyfrost/DataStorage/refs/heads/main/oneclient"; diff --git a/apps/oneclient/desktop/src/ext/updater.rs b/apps/oneclient/desktop/src/ext/updater.rs index 13474c3e..32d16990 100644 --- a/apps/oneclient/desktop/src/ext/updater.rs +++ b/apps/oneclient/desktop/src/ext/updater.rs @@ -65,8 +65,6 @@ pub async fn install_update(app: tauri::AppHandle) -> Result<(), drop(lock); app.restart(); - - Ok(()) } pub fn init(app: &tauri::AppHandle) -> tauri::Result<()> { @@ -76,19 +74,17 @@ pub fn init(app: &tauri::AppHandle) -> tauri::Result<()> { #[cfg(not(target_os = "linux"))] let updater_available = true; - if updater_available { - if let Some(window) = app.get_webview_window("main") { - window - .eval("window.__LAUNCHER_UPDATER__ = true;") - .expect("Failed to inject updater JS"); + if updater_available && let Some(window) = app.get_webview_window("main") { + window + .eval("window.__LAUNCHER_UPDATER__ = true;") + .expect("Failed to inject updater JS"); - window - .eval(&format!( - r#"window.__ONECLIENT_VERSION__ = "{}";"#, - Core::get().launcher_version, - )) - .expect("Failed to inject version JS"); - } + window + .eval(format!( + r#"window.__ONECLIENT_VERSION__ = "{}";"#, + Core::get().launcher_version, + )) + .expect("Failed to inject version JS"); } Ok(()) } diff --git a/apps/oneclient/desktop/src/lib.rs b/apps/oneclient/desktop/src/lib.rs index e066ce2b..71685e52 100644 --- a/apps/oneclient/desktop/src/lib.rs +++ b/apps/oneclient/desktop/src/lib.rs @@ -52,6 +52,7 @@ async fn initialize_core() -> LauncherResult<()> { } #[tracing::instrument(skip_all)] +#[allow(clippy::large_stack_frames)] async fn initialize_tauri(builder: tauri::Builder) -> LauncherResult { let router = taurpc::Router::new() .export_config( @@ -127,11 +128,11 @@ fn setup_window(handle: &tauri::AppHandle) -> Result<(), Box Result<(), Box(); unsafe { let ns_window = &*ns_window; if let Some(btn) = diff --git a/apps/oneclient/desktop/src/oneclient/bundle_updates.rs b/apps/oneclient/desktop/src/oneclient/bundle_updates.rs index 787d1c40..ae0d0166 100644 --- a/apps/oneclient/desktop/src/oneclient/bundle_updates.rs +++ b/apps/oneclient/desktop/src/oneclient/bundle_updates.rs @@ -26,7 +26,7 @@ fn get_cluster_lock(cluster_id: i64) -> Arc> { .clone() } -fn managed_bundle_key(provider: &Provider, package_id: &str) -> String { +fn managed_bundle_key(provider: Provider, package_id: &str) -> String { format!("m:{}:{}", provider.name(), package_id) } @@ -121,6 +121,7 @@ pub async fn check_bundle_updates( check_bundle_updates_inner(cluster_id, &overrides).await } +#[allow(clippy::too_many_lines)] async fn check_bundle_updates_inner( cluster_id: ClusterId, overrides: &[onelauncher_core::entity::cluster_bundle_overrides::Model], @@ -169,7 +170,7 @@ async fn check_bundle_updates_inner( if pkg.provider == Provider::Local && pkg.package_id == pkg.hash { None } else { - Some(managed_bundle_key(&pkg.provider, &pkg.package_id)) + Some(managed_bundle_key(pkg.provider, &pkg.package_id)) } }) .collect(); @@ -244,8 +245,9 @@ async fn check_bundle_updates_inner( enabled_count += 1; match &file.kind { - ModpackFileKind::Managed((pkg, version)) => { - let key = managed_bundle_key(&pkg.provider, &pkg.id); + ModpackFileKind::Managed(box_) => { + let (pkg, version) = &**box_; + let key = managed_bundle_key(pkg.provider, &pkg.id); tracing::trace!( bundle_name = %bundle.manifest.name, provider = %pkg.provider, @@ -255,7 +257,7 @@ async fn check_bundle_updates_inner( ); files_map.insert(key, (version.version_id.clone(), file.clone())); if file.hidden { - hidden_explicit_keys.insert(managed_bundle_key(&pkg.provider, &pkg.id)); + hidden_explicit_keys.insert(managed_bundle_key(pkg.provider, &pkg.id)); } // Dependencies that are not explicit files are treated as hidden mods @@ -263,7 +265,7 @@ async fn check_bundle_updates_inner( for dep in &version.dependencies { if let Some(dep_project_id) = &dep.project_id { hidden_dependency_keys - .insert(managed_bundle_key(&pkg.provider, dep_project_id)); + .insert(managed_bundle_key(pkg.provider, dep_project_id)); } } } @@ -411,7 +413,7 @@ async fn check_bundle_updates_inner( ); continue; }; - managed_bundle_key(&installed_pkg.provider, pkg_id) + managed_bundle_key(installed_pkg.provider, pkg_id) }; if let Some(ref bundle_name) = bundle_pkg.bundle_name { @@ -468,7 +470,13 @@ async fn check_bundle_updates_inner( bundle_name = %resolved_bundle_name, "Checking bundle package for updates" ); - if installed_version_id != &new_version_id { + if installed_version_id == &new_version_id { + tracing::debug!( + package_id = %pkg_id, + version = %installed_version_id, + "Bundle package is up to date" + ); + } else { tracing::info!( package_id = %pkg_id, installed_version = %installed_version_id, @@ -485,12 +493,6 @@ async fn check_bundle_updates_inner( new_file, installed_at: bundle_pkg.installed_at.unwrap_or_else(Utc::now), }); - } else { - tracing::debug!( - package_id = %pkg_id, - version = %installed_version_id, - "Bundle package is up to date" - ); } } else { not_in_bundle += 1; @@ -521,7 +523,7 @@ async fn check_bundle_updates_inner( // Without this, apply_single_update would try to replace a package that no longer exists. updates_available.retain(|u| { let file_id = match &u.new_file.kind { - ModpackFileKind::Managed((pkg, _)) => pkg.id.clone(), + ModpackFileKind::Managed(box_) => box_.0.id.clone(), ModpackFileKind::External(ext) => ext.sha1.clone(), }; !matches!( @@ -551,7 +553,7 @@ async fn check_bundle_updates_inner( } let file_key = match &file.kind { - ModpackFileKind::Managed((pkg, _)) => managed_bundle_key(&pkg.provider, &pkg.id), + ModpackFileKind::Managed(box_) => managed_bundle_key(box_.0.provider, &box_.0.id), ModpackFileKind::External(ext) => external_bundle_key(&ext.sha1), }; if planned_addition_keys.contains(&file_key) { @@ -559,24 +561,22 @@ async fn check_bundle_updates_inner( } let file_id = match &file.kind { - ModpackFileKind::Managed((pkg, _)) => pkg.id.clone(), + ModpackFileKind::Managed(box_) => box_.0.id.clone(), ModpackFileKind::External(ext) => ext.sha1.clone(), }; // Check user overrides if let Some(override_type) = overrides_map.get(&(bundle.manifest.name.clone(), file_id.clone())) - { - if *override_type + && *override_type == onelauncher_core::entity::cluster_bundle_overrides::OverrideType::Removed - { - tracing::info!( - bundle_name = %bundle.manifest.name, - file_id = %file_id, - "Skipping package addition due to user override 'Removed'" - ); - continue; - } + { + tracing::info!( + bundle_name = %bundle.manifest.name, + file_id = %file_id, + "Skipping package addition due to user override 'Removed'" + ); + continue; } tracing::info!( @@ -616,6 +616,7 @@ async fn check_bundle_updates_inner( }) } +#[allow(clippy::too_many_lines)] pub async fn get_bundles_with_update_status( cluster_id: ClusterId, ) -> LauncherResult> { @@ -648,7 +649,7 @@ pub async fn get_bundles_with_update_status( let key = if pkg_id == &bundle_pkg.package_hash { external_bundle_key(&bundle_pkg.package_hash) } else if let Some(installed_pkg) = all_linked_by_hash.get(&bundle_pkg.package_hash) { - managed_bundle_key(&installed_pkg.provider, pkg_id) + managed_bundle_key(installed_pkg.provider, pkg_id) } else { continue; }; @@ -683,19 +684,20 @@ pub async fn get_bundles_with_update_status( for file in &bundle.manifest.files { let update_status = match &file.kind { - ModpackFileKind::Managed((pkg, version)) => { - let key = managed_bundle_key(&pkg.provider, &pkg.id); + ModpackFileKind::Managed(box_) => { + let (pkg, version) = &**box_; + let key = managed_bundle_key(pkg.provider, &pkg.id); if let Some(installed) = installed_map.get(&key) { let installed_version = installed.bundle_version_id.as_deref().unwrap_or(""); - if installed_version != version.version_id { + if installed_version == version.version_id { + FileUpdateStatus::UpToDate + } else { has_updates = true; FileUpdateStatus::UpdateAvailable { installed_version_id: installed_version.to_string(), new_version_id: version.version_id.clone(), } - } else { - FileUpdateStatus::UpToDate } } else { let key = (bundle.manifest.name.clone(), pkg.id.clone()); @@ -767,6 +769,7 @@ pub struct BundleWithUpdateStatus { pub has_updates: bool, } +#[allow(clippy::too_many_lines)] async fn apply_single_update( update: &BundlePackageUpdate, overrides: &[onelauncher_core::entity::cluster_bundle_overrides::Model], @@ -786,7 +789,8 @@ async fn apply_single_update( // Download the new version first. If it fails the old package remains untouched. let model = match &update.new_file.kind { - ModpackFileKind::Managed((pkg, version)) => { + ModpackFileKind::Managed(box_) => { + let (pkg, version) = &**box_; tracing::debug!( package_id = %pkg.id, version_id = %version.version_id, @@ -815,7 +819,7 @@ async fn apply_single_update( api::packages::link_package(&model, &cluster, Some(true)).await?; let version_id = match &update.new_file.kind { - ModpackFileKind::Managed((_, version)) => version.version_id.clone(), + ModpackFileKind::Managed(box_) => box_.1.version_id.clone(), ModpackFileKind::External(ext) => ext.sha1.clone(), }; @@ -834,7 +838,7 @@ async fn apply_single_update( // Check if this package should be disabled based on user overrides (passed in from caller) let file_id = match &update.new_file.kind { - ModpackFileKind::Managed((pkg, _)) => pkg.id.clone(), + ModpackFileKind::Managed(box_) => box_.0.id.clone(), ModpackFileKind::External(ext) => ext.sha1.clone(), }; @@ -919,12 +923,13 @@ async fn apply_single_removal(removal: &BundlePackageRemoval) -> LauncherResult< Ok(()) } +#[allow(clippy::too_many_lines)] async fn apply_single_addition( addition: &BundlePackageAddition, overrides: &[onelauncher_core::entity::cluster_bundle_overrides::Model], ) -> LauncherResult { let file_id = match &addition.new_file.kind { - ModpackFileKind::Managed((pkg, _)) => pkg.id.clone(), + ModpackFileKind::Managed(box_) => box_.0.id.clone(), ModpackFileKind::External(ext) => ext.sha1.clone(), }; @@ -940,7 +945,8 @@ async fn apply_single_addition( .ok_or_else(|| anyhow::anyhow!("cluster with id {} not found", addition.cluster_id))?; match &addition.new_file.kind { - ModpackFileKind::Managed((pkg, version)) => { + ModpackFileKind::Managed(box_) => { + let (pkg, version) = &**box_; tracing::debug!( package_id = %pkg.id, version_id = %version.version_id, @@ -1077,6 +1083,7 @@ pub struct ApplyBundleUpdatesResult { pub additions_failed: Vec, } +#[allow(clippy::too_many_lines)] pub async fn apply_bundle_updates( cluster_id: ClusterId, ) -> LauncherResult { @@ -1098,7 +1105,7 @@ pub async fn apply_bundle_updates( for removal in check_result.removals_available { match apply_single_removal(&removal).await { - Ok(_) => { + Ok(()) => { removals_applied.push(removal); } Err(e) => { @@ -1118,7 +1125,7 @@ pub async fn apply_bundle_updates( updates_applied.push(update); } Err(e) => { - let msg = format!("Failed to update bundle package: {}", e); + let msg = format!("Failed to update bundle package: {e}"); send_error!("{}", msg); updates_failed.push(msg); } @@ -1127,7 +1134,7 @@ pub async fn apply_bundle_updates( for addition in check_result.additions_available { let file_id = match &addition.new_file.kind { - ModpackFileKind::Managed((pkg, _)) => pkg.id.clone(), + ModpackFileKind::Managed(box_) => box_.0.id.clone(), ModpackFileKind::External(ext) => ext.sha1.clone(), }; match apply_single_addition(&addition, &cluster_overrides).await { @@ -1135,7 +1142,7 @@ pub async fn apply_bundle_updates( additions_applied.push(addition); } Err(e) => { - let msg = format!("Failed to install new bundle package '{}': {}", file_id, e); + let msg = format!("Failed to install new bundle package '{file_id}': {e}"); send_error!("{}", msg); additions_failed.push(msg); } diff --git a/apps/oneclient/desktop/src/oneclient/bundle_updates_test.rs b/apps/oneclient/desktop/src/oneclient/bundle_updates_test.rs index 9ecb62ca..2d1de71c 100644 --- a/apps/oneclient/desktop/src/oneclient/bundle_updates_test.rs +++ b/apps/oneclient/desktop/src/oneclient/bundle_updates_test.rs @@ -2,7 +2,7 @@ mod tests { use onelauncher_core::entity::loader::GameLoader; use onelauncher_core::store::{Core, CoreOptions}; - use std::path::PathBuf; + use tokio::fs; use crate::oneclient::bundle_updates::{apply_bundle_updates, check_bundle_updates}; @@ -13,7 +13,8 @@ mod tests { // We only run this if we ignore it by default, since it hits the network and modifies DB // but we can run it explicitly. #[tokio::test] - #[ignore] + #[ignore = "touches true files and takes long"] + #[allow(clippy::too_many_lines, clippy::items_after_statements)] async fn test_bundle_updates_e2e() { // 1. Initialize DB and paths Core::initialize(CoreOptions::default()).await.unwrap(); @@ -132,7 +133,7 @@ mod tests { // Remove it from the database and filesystem so the updater thinks it's missing. // record_override=false: this simulates a missing package, not a deliberate user removal. - println!("Removing package hash: {}", hash_to_remove); + println!("Removing package hash: {hash_to_remove}"); onelauncher_core::api::packages::remove_package(cluster.id, hash_to_remove, false) .await .unwrap(); @@ -187,7 +188,8 @@ mod tests { } #[tokio::test] - #[ignore] + #[ignore = "touches true files and takes long"] + #[allow(clippy::too_many_lines, clippy::items_after_statements)] async fn test_bundle_user_overrides() { // 1. Initialize DB and paths Core::initialize(CoreOptions::default()).await.unwrap(); @@ -300,10 +302,9 @@ mod tests { let is_offered_as_addition = check_removed.additions_available.iter().any(|a| { let file_id = match &a.new_file.kind { - onelauncher_core::api::packages::modpack::data::ModpackFileKind::Managed(( - pkg, - _, - )) => pkg.id.clone(), + onelauncher_core::api::packages::modpack::data::ModpackFileKind::Managed(box_) => { + box_.0.id.clone() + } onelauncher_core::api::packages::modpack::data::ModpackFileKind::External(ext) => { ext.sha1.clone() } @@ -373,8 +374,8 @@ mod tests { .new_file; let file_id = match &updated_pkg_hash.kind { - onelauncher_core::api::packages::modpack::data::ModpackFileKind::Managed((pkg, _)) => { - pkg.id.clone() + onelauncher_core::api::packages::modpack::data::ModpackFileKind::Managed(box_) => { + box_.0.id.clone() } onelauncher_core::api::packages::modpack::data::ModpackFileKind::External(ext) => { ext.sha1.clone() diff --git a/apps/oneclient/desktop/src/oneclient/bundles.rs b/apps/oneclient/desktop/src/oneclient/bundles.rs index 2e76ec1f..c0226ab5 100644 --- a/apps/oneclient/desktop/src/oneclient/bundles.rs +++ b/apps/oneclient/desktop/src/oneclient/bundles.rs @@ -14,12 +14,12 @@ use tokio::sync::{OnceCell, RwLock}; /// e.g. /// ```json /// { -/// "versions": { -/// "1.21.5": { -/// "fabric": ["/generated/hud-fabric-1.21.5.mrpack"], -/// "forge": ["/generated/hud-forge-1.21.5.mrpack"] -/// } -/// }, +/// "versions": { +/// "1.21.5": { +/// "fabric": ["/generated/hud-fabric-1.21.5.mrpack"], +/// "forge": ["/generated/hud-forge-1.21.5.mrpack"] +/// } +/// }, /// } /// ``` #[derive(Default, Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] @@ -59,20 +59,20 @@ impl BundlesManager { // Fast path: check cache under read lock. let bundles_lock = self.bundles.read().await; - if let Some(entry) = bundles_lock.get(mc_version) { - if let Some(bundles) = entry.get(&loader) { - return Ok(bundles.clone()); - } + if let Some(entry) = bundles_lock.get(mc_version) + && let Some(bundles) = entry.get(&loader) + { + return Ok(bundles.clone()); } drop(bundles_lock); // Slow path: acquire write lock and re-check before populating (double-checked locking). // This closes the TOCTOU gap between dropping the read lock and acquiring the write lock. let mut bundles_lock = self.bundles.write().await; - if let Some(entry) = bundles_lock.get(mc_version) { - if let Some(bundles) = entry.get(&loader) { - return Ok(bundles.clone()); - } + if let Some(entry) = bundles_lock.get(mc_version) + && let Some(bundles) = entry.get(&loader) + { + return Ok(bundles.clone()); } let mut found = Vec::new(); @@ -88,7 +88,7 @@ impl BundlesManager { // we will be first checking the disk cache, if that fails we fetch from remote for path in paths { - let Some(file_name) = path.split('/').last() else { + let Some(file_name) = path.split('/').next_back() else { tracing::error!("no bundle name was found in path: {path}"); continue; }; @@ -199,14 +199,14 @@ async fn download_and_load_bundle( .headers() .get(reqwest::header::ETAG) .and_then(|v| v.to_str().ok()) - .map(|s| s.to_string()); + .map(std::string::ToString::to_string); let stored_etag: Option = tokio::fs::read_to_string(&etag_path).await.ok(); if let (Some(server), Some(stored)) = (&server_etag, &stored_etag) { // ETag comparison: most reliable cache validation method. if server == stored { tracing::debug!("bundle cache hit via ETag for: {url}"); - return Ok(ModpackFormat::from_file(disk_path).await?); + return ModpackFormat::from_file(disk_path).await; } } else { // Fall back to Content-Length comparison when no ETag is available. @@ -219,7 +219,7 @@ async fn download_and_load_bundle( if let Some(length) = content_length { let file_size = io::stat(disk_path).await.map(|m| m.len()).unwrap_or(0); if length == file_size { - return Ok(ModpackFormat::from_file(disk_path).await?); + return ModpackFormat::from_file(disk_path).await; } } // If neither ETag nor Content-Length are available, fall through to re-download. @@ -230,13 +230,13 @@ async fn download_and_load_bundle( status = %res.status(), "failed to validate remote bundle cache for {url}; using cached local bundle" ); - return Ok(ModpackFormat::from_file(disk_path).await?); + return ModpackFormat::from_file(disk_path).await; } Err(e) => { tracing::warn!( "failed to validate remote bundle cache for {url}: {e}; using cached local bundle" ); - return Ok(ModpackFormat::from_file(disk_path).await?); + return ModpackFormat::from_file(disk_path).await; } } } @@ -245,15 +245,14 @@ async fn download_and_load_bundle( http::download(Method::GET, &url, disk_path, None, None).await?; // After a fresh download, persist the server ETag for next time. - if let Ok(head_res) = http::request(Method::HEAD, &url).await { - if let Some(etag) = head_res + if let Ok(head_res) = http::request(Method::HEAD, &url).await + && let Some(etag) = head_res .headers() .get(reqwest::header::ETAG) .and_then(|v| v.to_str().ok()) - { - let _ = tokio::fs::write(&etag_path, etag).await; - } + { + let _ = tokio::fs::write(&etag_path, etag).await; } - Ok(ModpackFormat::from_file(disk_path).await?) + ModpackFormat::from_file(disk_path).await } diff --git a/apps/oneclient/desktop/src/oneclient/clusters.rs b/apps/oneclient/desktop/src/oneclient/clusters.rs index 3291aa34..4fdd41e3 100644 --- a/apps/oneclient/desktop/src/oneclient/clusters.rs +++ b/apps/oneclient/desktop/src/oneclient/clusters.rs @@ -13,37 +13,37 @@ use serde::{Deserialize, Serialize}; /// e.g. /// ```json /// { -/// "clusters": [ -/// { -/// "major_version": 21, -/// "name": "Tricky Trials", -/// "art": "/versions/art/Tricky_Trials.png", -/// "entries": [ -/// { -/// "minor_version": 5, -/// "loader": "fabric", -/// "tags": ["PvP", "Survival"] -/// }, -/// { -/// "minor_version": 5, -/// "loader": "forge", -/// "tags": ["PvP", "Survival"] -/// } -/// ] -/// }, -/// { -/// "major_version": 20, -/// "name": "Trails & Tales", -/// "art": "/versions/art/Trails_Tales.png", -/// "entries": [ -/// { -/// "minor_version": 5, -/// "loader": "fabric", -/// "tags": ["PvP", "Survival"] -/// } -/// ] -/// } -/// ] +/// "clusters": [ +/// { +/// "major_version": 21, +/// "name": "Tricky Trials", +/// "art": "/versions/art/Tricky_Trials.png", +/// "entries": [ +/// { +/// "minor_version": 5, +/// "loader": "fabric", +/// "tags": ["PvP", "Survival"] +/// }, +/// { +/// "minor_version": 5, +/// "loader": "forge", +/// "tags": ["PvP", "Survival"] +/// } +/// ] +/// }, +/// { +/// "major_version": 20, +/// "name": "Trails & Tales", +/// "art": "/versions/art/Trails_Tales.png", +/// "entries": [ +/// { +/// "minor_version": 5, +/// "loader": "fabric", +/// "tags": ["PvP", "Survival"] +/// } +/// ] +/// } +/// ] /// } /// ``` #[derive(specta::Type, Deserialize, Serialize)] @@ -90,7 +90,9 @@ pub async fn get_data_storage_versions() -> LauncherResult LauncherResult { @@ -117,6 +119,7 @@ pub async fn cache_art_image(path: &str) -> LauncherResult { } /// Re-download an art image and overwrite the on-disk cache. +/// /// Errors are silently ignored — the existing cached version is kept on failure. /// Call this from `tokio::spawn` so it runs fully in the background. pub async fn refresh_art_cache(path: &str) { @@ -162,7 +165,7 @@ pub async fn init_clusters() -> LauncherResult<()> { Ok(()) } -fn cluster_name(mc_version: &str, loader: &GameLoader) -> String { +fn cluster_name(mc_version: &str, loader: GameLoader) -> String { format!("{mc_version} {loader}") } @@ -171,7 +174,7 @@ async fn create_cluster_if_not_exist( mc_loader: GameLoader, mc_loader_version: Option<&str>, ) -> LauncherResult> { - let name = cluster_name(mc_version, &mc_loader); + let name = cluster_name(mc_version, mc_loader); let cluster = onelauncher_core::api::cluster::dao::get_cluster_by_folder_name(Path::new(&name)).await?; diff --git a/apps/oneclient/desktop/src/oneclient/mod.rs b/apps/oneclient/desktop/src/oneclient/mod.rs index 573f5257..60382954 100644 --- a/apps/oneclient/desktop/src/oneclient/mod.rs +++ b/apps/oneclient/desktop/src/oneclient/mod.rs @@ -30,6 +30,7 @@ pub async fn initialize_oneclient() { }); } +#[allow(clippy::too_many_lines)] async fn check_and_apply_all_bundle_updates() { BUNDLE_SYNCING.store(true, Ordering::Relaxed); tracing::info!("checking for bundle updates..."); @@ -120,7 +121,7 @@ async fn check_and_apply_all_bundle_updates() { for addition in &result.additions_applied { let file_id = match &addition.new_file.kind { - onelauncher_core::api::packages::modpack::data::ModpackFileKind::Managed((pkg, _)) => pkg.id.clone(), + onelauncher_core::api::packages::modpack::data::ModpackFileKind::Managed(box_) => box_.0.id.clone(), onelauncher_core::api::packages::modpack::data::ModpackFileKind::External(ext) => ext.sha1.clone(), }; tracing::info!( @@ -147,13 +148,13 @@ async fn check_and_apply_all_bundle_updates() { if total_updates_applied > 0 || total_removals_applied > 0 || total_additions_applied > 0 { let mut message_parts = Vec::new(); if total_updates_applied > 0 { - message_parts.push(format!("{} mod(s) updated", total_updates_applied)); + message_parts.push(format!("{total_updates_applied} mod(s) updated")); } if total_removals_applied > 0 { - message_parts.push(format!("{} mod(s) removed", total_removals_applied)); + message_parts.push(format!("{total_removals_applied} mod(s) removed")); } if total_additions_applied > 0 { - message_parts.push(format!("{} mod(s) added", total_additions_applied)); + message_parts.push(format!("{total_additions_applied} mod(s) added")); } send_info!("Bundle sync: {}", message_parts.join(", ")); tracing::info!( diff --git a/apps/oneclient/frontend/src/bindings.gen.ts b/apps/oneclient/frontend/src/bindings.gen.ts index e54a761e..ddaf56a0 100644 --- a/apps/oneclient/frontend/src/bindings.gen.ts +++ b/apps/oneclient/frontend/src/bindings.gen.ts @@ -57,7 +57,7 @@ export type LauncherError = { type: "DirError"; data: DirectoryError } | { type: export type ManagedPackage = { id: string; slug: string; provider: Provider; package_type: PackageType; name: string; short_desc: string; body: ManagedPackageBody; /** - * Won't have all versions for some providers, like CurseForge. + * Won't have all versions for some providers, like `CurseForge`. * Try making a request to get the versions if needed */ version_ids: string[]; mc_versions: string[]; loaders: GameLoader[]; icon_url: string | null; created: string; updated: string; client: PackageSide; server: PackageSide; categories: PackageCategories; license: PackageLicense | null; author: PackageAuthor; links: PackageLinks; status: PackageStatus; downloads: number; gallery: PackageGallery[] } @@ -313,8 +313,32 @@ export type VersionType = */ "old_beta" -const ARGS_MAP = { 'core':'{"getPackage":["provider","slug"],"updateClusterById":["id","request"],"setClusterStage":["id","stage"],"refreshAccount":["uuid"],"readSettings":[],"getProfileOrDefault":["name"],"getMultiplePackages":["provider","slugs"],"getProcessLogTail":["id","max_lines"],"fetchLoggedInProfile":["access_token"],"launchCluster":["id","uuid","search_for_java"],"togglePackage":["cluster_id","package_hash"],"changeCape":["access_token","cape_uuid"],"removeCape":["access_token"],"open":["input"],"getPackageBody":["provider","body"],"getClusters":[],"removePackage":["cluster_id","package_hash"],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"setDiscordRPCMessage":["message"],"getUsersFromAuthor":["provider","author"],"getClusterById":["id"],"getWorlds":["id"],"openMsaLogin":[],"getRunningProcesses":[],"isClusterRunning":["cluster_id"],"getGameVersions":[],"getRunningProcessesByClusterId":["cluster_id"],"killProcess":["pid"],"removeUser":["uuid"],"refreshAccounts":[],"searchPackages":["provider","query"],"getLinkedPackages":["cluster_id"],"getGlobalProfile":[],"fetchMinecraftProfile":["uuid"],"getUser":["uuid"],"installModpack":["modpack","cluster_id"],"createCluster":["options"],"changeSkin":["access_token","skin_url","skin_variant"],"getScreenshots":["id"],"getUsers":[],"convertUsernameUUID":["username_uuid"],"getLogByName":["id","name"],"createSettingsProfile":["name"],"getDefaultUser":["fallback"],"syncCluster":["cluster_id"],"updateClusterProfile":["name","profile"],"removeCluster":["id"],"writeSettings":["setting"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getLoadersForVersion":["mc_version"],"setDefaultUser":["uuid"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"getLogs":["id"]}', 'oneclient':'{"installUpdate":[],"getBundlesFor":["cluster_id"],"extractBundleOverrides":["bundle_path","cluster_id"],"updateBundlePackages":["cluster_id"],"downloadPackageFromBundle":["package","cluster_id","bundle_name","skip_compatibility"],"cacheArt":["path"],"refreshArt":["path"],"checkForUpdate":[],"getVersions":[],"getClustersGroupedByMajor":[],"isBundleSyncing":[]}', 'events':'{"process":["event"],"ingress":["event"],"message":["event"]}', 'folders':'{"openCluster":["folder_name"],"fromCluster":["folder_name"]}', 'debug':'{"getBuildTimestamp":[],"getGitCommitHash":[],"getPlatform":[],"getType":[],"getLocale":[],"openDevTools":[],"getFamily":[],"getOsVersion":[],"getPackageVersion":[],"getArch":[],"isInDev":[]}' } -export type Router = { 'core': { getClusters: () => Promise, +const ARGS_MAP = { 'folders':'{"openCluster":["folder_name"],"fromCluster":["folder_name"]}', 'core':'{"getGameVersions":[],"getScreenshots":["id"],"setDefaultUser":["uuid"],"removeUser":["uuid"],"isClusterRunning":["cluster_id"],"killProcess":["pid"],"updateClusterById":["id","request"],"writeSettings":["setting"],"getWorlds":["id"],"setDiscordRPCMessage":["message"],"removeCape":["access_token"],"getLinkedPackages":["cluster_id"],"getPackageBody":["provider","body"],"removeCluster":["id"],"syncCluster":["cluster_id"],"launchCluster":["id","uuid","search_for_java"],"getLogByName":["id","name"],"getProfileOrDefault":["name"],"getClusterById":["id"],"getLogs":["id"],"getLoadersForVersion":["mc_version"],"openMsaLogin":[],"getRunningProcessesByClusterId":["cluster_id"],"getGlobalProfile":[],"refreshAccounts":[],"getRunningProcesses":[],"readSettings":[],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"getPackage":["provider","slug"],"fetchMinecraftProfile":["uuid"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"setClusterStage":["id","stage"],"createSettingsProfile":["name"],"open":["input"],"createCluster":["options"],"updateClusterProfile":["name","profile"],"refreshAccount":["uuid"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getUsers":[],"getUser":["uuid"],"getUsersFromAuthor":["provider","author"],"getMultiplePackages":["provider","slugs"],"changeCape":["access_token","cape_uuid"],"changeSkin":["access_token","skin_url","skin_variant"],"convertUsernameUUID":["username_uuid"],"removePackage":["cluster_id","package_hash"],"searchPackages":["provider","query"],"getClusters":[],"togglePackage":["cluster_id","package_hash"],"installModpack":["modpack","cluster_id"],"getProcessLogTail":["id","max_lines"],"fetchLoggedInProfile":["access_token"],"getDefaultUser":["fallback"]}', 'debug':'{"getBuildTimestamp":[],"getType":[],"getPackageVersion":[],"openDevTools":[],"getPlatform":[],"getLocale":[],"isInDev":[],"getArch":[],"getOsVersion":[],"getGitCommitHash":[],"getFamily":[]}', 'oneclient':'{"installUpdate":[],"getClustersGroupedByMajor":[],"getBundlesFor":["cluster_id"],"extractBundleOverrides":["bundle_path","cluster_id"],"checkForUpdate":[],"downloadPackageFromBundle":["package","cluster_id","bundle_name","skip_compatibility"],"updateBundlePackages":["cluster_id"],"cacheArt":["path"],"refreshArt":["path"],"isBundleSyncing":[],"getVersions":[]}', 'events':'{"message":["event"],"ingress":["event"],"process":["event"]}' } +export type Router = { 'folders': { fromCluster: (folderName: string) => Promise, +openCluster: (folderName: string) => Promise }, +'debug': { openDevTools: () => Promise, +isInDev: () => Promise, +getArch: () => Promise, +getFamily: () => Promise, +getLocale: () => Promise, +getType: () => Promise, +getPlatform: () => Promise, +getOsVersion: () => Promise, +getGitCommitHash: () => Promise, +getBuildTimestamp: () => Promise, +getPackageVersion: () => Promise }, +'oneclient': { getClustersGroupedByMajor: () => Promise>, +getBundlesFor: (clusterId: number) => Promise, +getVersions: () => Promise, +extractBundleOverrides: (bundlePath: string, clusterId: number) => Promise, +checkForUpdate: () => Promise, +installUpdate: () => Promise, +downloadPackageFromBundle: (package: ModpackFileKind, clusterId: number, bundleName: string, skipCompatibility: boolean | null) => Promise, +updateBundlePackages: (clusterId: number) => Promise, +isBundleSyncing: () => Promise, +cacheArt: (path: string) => Promise, +refreshArt: (path: string) => Promise }, +'core': { getClusters: () => Promise, getClusterById: (id: number) => Promise, removeCluster: (id: number) => Promise, createCluster: (options: CreateCluster) => Promise, @@ -370,31 +394,7 @@ setDiscordRPCMessage: (message: string) => Promise, open: (input: string) => Promise }, 'events': { ingress: (event: IngressPayload) => Promise, message: (event: MessagePayload) => Promise, -process: (event: ProcessPayload) => Promise }, -'oneclient': { getClustersGroupedByMajor: () => Promise>, -getBundlesFor: (clusterId: number) => Promise, -getVersions: () => Promise, -extractBundleOverrides: (bundlePath: string, clusterId: number) => Promise, -checkForUpdate: () => Promise, -installUpdate: () => Promise, -downloadPackageFromBundle: (package: ModpackFileKind, clusterId: number, bundleName: string, skipCompatibility: boolean | null) => Promise, -updateBundlePackages: (clusterId: number) => Promise, -isBundleSyncing: () => Promise, -cacheArt: (path: string) => Promise, -refreshArt: (path: string) => Promise }, -'folders': { fromCluster: (folderName: string) => Promise, -openCluster: (folderName: string) => Promise }, -'debug': { openDevTools: () => Promise, -isInDev: () => Promise, -getArch: () => Promise, -getFamily: () => Promise, -getLocale: () => Promise, -getType: () => Promise, -getPlatform: () => Promise, -getOsVersion: () => Promise, -getGitCommitHash: () => Promise, -getBuildTimestamp: () => Promise, -getPackageVersion: () => Promise } }; +process: (event: ProcessPayload) => Promise } }; export type { InferCommandOutput } diff --git a/apps/oneclient/frontend/src/components/Bundle/ModCard.tsx b/apps/oneclient/frontend/src/components/Bundle/ModCard.tsx index 71eecd1a..f6970cad 100644 --- a/apps/oneclient/frontend/src/components/Bundle/ModCard.tsx +++ b/apps/oneclient/frontend/src/components/Bundle/ModCard.tsx @@ -60,11 +60,11 @@ function getFileKey(file: ModpackFile): string { if ('Managed' in file.kind) return `managed:${file.kind.Managed[0].id}`; if ('External' in file.kind) - return `external:${file.kind.External.sha1 ?? file.kind.External.url ?? file.kind.External.name}`; + return `external:${file.kind.External.sha1 || file.kind.External.url || file.kind.External.name}`; return 'unknown'; } -const modMetadataCache = new Map>(); +const modMetadataCache: Map> = new Map(); function fetchModMetaData(file: ModpackFile, useVerticalGridLayout?: boolean): Promise { const key = getFileKey(file); @@ -136,16 +136,17 @@ export function ModCard({ file, cluster }: ModCardProps) { if (!cancelled) setModMetadata(meta); }).catch(() => {}); - return () => { cancelled = true; }; + return () => { + cancelled = true; + }; }, [file, useVerticalGridLayout]); const kind = file.kind; - // Directory-based packages (folders dropped into resourcepacks/shaderpacks/datapacks) - // cannot be toggled via .disabled rename — skip toggle mode for them. - const isDirectory = useMemo(() => - 'External' in kind && !kind.External.name.includes('.'), - [kind]); - const effectiveToggleMode = useToggleMode && !isDirectory; + // Directory-based packages (folders dropped into resourcepacks/shaderpacks/datapacks) + // cannot be toggled via .disabled rename — skip toggle mode for them. + const isDirectory = useMemo(() => + 'External' in kind && !kind.External.name.includes('.'), [kind]); + const effectiveToggleMode = useToggleMode && !isDirectory; const isInstalled = useMemo(() => { if (installedPackages) if ('Managed' in kind) { @@ -161,18 +162,18 @@ export function ModCard({ file, cluster }: ModCardProps) { // In toggle mode, "selected" = enabled (file_name doesn't end with .disabled) const isFileEnabled = useMemo(() => { - if (!effectiveToggleMode) - return true; - if ('Managed' in kind) { - const primary = kind.Managed[1].files.find(f => f.primary) ?? kind.Managed[1].files[0]; - return !primary?.file_name.endsWith('.disabled'); - } - return !kind.External.name.endsWith('.disabled'); - }, [effectiveToggleMode, kind]); - const [isSelected, setSelected] = useState(effectiveToggleMode ? isFileEnabled : isInstalled); - useEffect(() => { - setSelected(effectiveToggleMode ? isFileEnabled : isInstalled); - }, [isInstalled, effectiveToggleMode, isFileEnabled]); + if (!effectiveToggleMode) + return true; + if ('Managed' in kind) { + const primary = kind.Managed[1].files.find(f => f.primary) ?? kind.Managed[1].files[0]; + return !primary.file_name.endsWith('.disabled'); + } + return !kind.External.name.endsWith('.disabled'); + }, [effectiveToggleMode, kind]); + const [isSelected, setSelected] = useState(effectiveToggleMode ? isFileEnabled : isInstalled); + useEffect(() => { + setSelected(effectiveToggleMode ? isFileEnabled : isInstalled); + }, [isInstalled, effectiveToggleMode, isFileEnabled]); const download = useCommandMut(async () => { if ('Managed' in kind) { @@ -223,11 +224,11 @@ export function ModCard({ file, cluster }: ModCardProps) { }); const handleOnClick = () => { - // Folder-based packages (resource packs, shader packs, data packs as directories) - // cannot be toggled or removed — treat them as entirely non-interactive. - if (isDirectory) - return; - if (effectiveToggleMode) + // Folder-based packages (resource packs, shader packs, data packs as directories) + // cannot be toggled or removed — treat them as entirely non-interactive. + if (isDirectory) + return; + if (effectiveToggleMode) (async () => { await toggle.mutateAsync(); await queryClient.invalidateQueries({ queryKey: ['getLinkedPackages', cluster.id] }); diff --git a/apps/oneclient/frontend/src/components/Bundle/ModList.tsx b/apps/oneclient/frontend/src/components/Bundle/ModList.tsx index 4f5ab471..c66a755a 100644 --- a/apps/oneclient/frontend/src/components/Bundle/ModList.tsx +++ b/apps/oneclient/frontend/src/components/Bundle/ModList.tsx @@ -1,5 +1,5 @@ import type { ClusterModel, ModpackArchive } from '@/bindings.gen'; -import { Bundle, ModCardContext, getModMetaDataName } from '@/components'; +import { Bundle, getModMetaDataName, ModCardContext } from '@/components'; import { useSettings } from '@/hooks/useSettings'; import { Button, Tab, TabContent, TabList, TabPanel, Tabs, TextField } from '@onelauncher/common/components'; import { SearchMdIcon } from '@untitled-theme/icons-react'; @@ -77,30 +77,30 @@ export function ModList({ bundles, cluster, selectedTab, onTabChange, toggleBund {isSearching ? ( -
- -
- ) +
+ +
+ ) : ( - - {nonEmptyBundles.map((bundleData) => { - const isToggle = toggleBundlePaths?.has(bundleData.path) ?? false; - const content = ; + + {nonEmptyBundles.map((bundleData) => { + const isToggle = toggleBundlePaths?.has(bundleData.path) ?? false; + const content = ; - return ( - - {isToggle - ? ( - - {content} - - ) - : content} - - ); - })} - - )} + return ( + + {isToggle + ? ( + + {content} + + ) + : content} + + ); + })} + + )} ); } diff --git a/apps/oneclient/frontend/src/components/DownloadMods.tsx b/apps/oneclient/frontend/src/components/DownloadMods.tsx index 911fdbf3..6b100da8 100644 --- a/apps/oneclient/frontend/src/components/DownloadMods.tsx +++ b/apps/oneclient/frontend/src/components/DownloadMods.tsx @@ -174,6 +174,7 @@ function DownloadingMods({ mods, setOpen, nextPath }: { mods: ModDataArray; setO }; downloadAll(); + // eslint-disable-next-line react-hooks/exhaustive-deps -- download is not stable, adding it would cause infinite loops }, [mods]); useEffect(() => { diff --git a/apps/oneclient/frontend/src/components/SkinViewer.tsx b/apps/oneclient/frontend/src/components/SkinViewer.tsx index 1feb9dd5..4874ea0a 100644 --- a/apps/oneclient/frontend/src/components/SkinViewer.tsx +++ b/apps/oneclient/frontend/src/components/SkinViewer.tsx @@ -94,6 +94,7 @@ export function SkinViewer({ return () => { viewer.dispose(); }; + // eslint-disable-next-line react-hooks/exhaustive-deps -- intentional mount-only initialization }, []); useEffect(() => { diff --git a/apps/oneclient/frontend/src/hooks/useSettings.ts b/apps/oneclient/frontend/src/hooks/useSettings.ts index 395b5376..b57973f9 100644 --- a/apps/oneclient/frontend/src/hooks/useSettings.ts +++ b/apps/oneclient/frontend/src/hooks/useSettings.ts @@ -19,7 +19,7 @@ export function useSettings() { const createSetting = useMemo(() => (key: TKey): [Settings[TKey], Setter] => { return [setting(key), value => setSetting(key, value)]; - }, [setting]); + }, [setting, setSetting]); return { setting, setSetting, createSetting }; } @@ -62,7 +62,7 @@ export function useClusterProfile(cluster: ClusterModel) { throw new Error('No settings profile name'); await bindings.core.updateClusterProfile(name, { ...emptyUpdate, ...update }); profileSrc.refetch(); - }, [profileName, cluster.name, cluster.id]); + }, [profileName, cluster.name, cluster.id, profileSrc]); // const updateProfile = useMemo(() => (update: Partial) => setProfile({ ...profile.data, ...update }), [setProfile, profile.data]); return { profile, setProfile, updateProfile }; } diff --git a/apps/oneclient/frontend/src/routes/app/account/skins.tsx b/apps/oneclient/frontend/src/routes/app/account/skins.tsx index 714e78d7..100fdb2f 100644 --- a/apps/oneclient/frontend/src/routes/app/account/skins.tsx +++ b/apps/oneclient/frontend/src/routes/app/account/skins.tsx @@ -10,7 +10,7 @@ import { save } from '@tauri-apps/plugin-dialog'; import { exists, mkdir, readTextFile, writeFile, writeTextFile } from '@tauri-apps/plugin-fs'; import { Download01Icon, PlusIcon, Trash01Icon } from '@untitled-theme/icons-react'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { CrouchAnimation, FlyingAnimation, HitAnimation, IdleAnimation, WalkingAnimation } from 'skinview3d'; interface Skin { @@ -120,11 +120,11 @@ function RouteComponent() { if (!profileData) return; setCapes([{ url: '', id: '' }, ...profileData.capes.map(cape => ({ url: cape.url, id: cape.id }))]); - }, []); + }, [profileData]); const [skins, setSkins, loaded] = useSkinHistory(); const [selectedSkin, setSelectedSkin] = useState({ skin_url: getSkinUrl(null), is_slim: false }); - const skinData: Skin = { is_slim: profileData?.skins[0].variant === 'slim', skin_url: getSkinUrl(profileData?.skins[0].url), cape_url: playerData?.cape_url ?? '' }; + const skinData: Skin = useMemo(() => ({ is_slim: profileData?.skins[0].variant === 'slim', skin_url: getSkinUrl(profileData?.skins[0].url), cape_url: playerData?.cape_url ?? '' }), [playerData?.cape_url, profileData?.skins]); useEffect(() => { if (!loaded) @@ -133,7 +133,7 @@ function RouteComponent() { setSkins(prev => [...prev, skinData]); setSelectedSkin(skinData); setSelectedCape(skinData.cape_url ?? ''); - }, [loaded]); + }, [loaded, setSkins, skinData]); const importFromURL = (url: string) => { setSkins(prev => [...prev, { is_slim: false, skin_url: url }]); diff --git a/apps/oneclient/frontend/src/routes/app/cluster/datapacks.tsx b/apps/oneclient/frontend/src/routes/app/cluster/datapacks.tsx index d3cc4d83..6b393b8b 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/datapacks.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/datapacks.tsx @@ -26,8 +26,7 @@ function RouteComponent() { const customBundle = useCustomBundle(bundles, installedPackages, cluster, 'datapack'); const allBundles = useMemo(() => - customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, - [filteredBundles, customBundle]); + customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, [filteredBundles, customBundle]); const customTogglePaths = useMemo(() => new Set(['__custom__']), []); diff --git a/apps/oneclient/frontend/src/routes/app/cluster/mods.tsx b/apps/oneclient/frontend/src/routes/app/cluster/mods.tsx index a3ed78e1..0a7e2257 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/mods.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/mods.tsx @@ -32,8 +32,7 @@ function RouteComponent() { const customBundle = useCustomBundle(bundles, installedPackages, cluster, 'mod'); const allBundles = useMemo(() => - customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, - [filteredBundles, customBundle]); + customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, [filteredBundles, customBundle]); const customTogglePaths = useMemo(() => new Set(['__custom__']), []); diff --git a/apps/oneclient/frontend/src/routes/app/cluster/resource-packs.tsx b/apps/oneclient/frontend/src/routes/app/cluster/resource-packs.tsx index fea360b5..949eaabf 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/resource-packs.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/resource-packs.tsx @@ -1,8 +1,8 @@ import type { ModCardContextApi } from '@/components'; import { ModCardContext, ModList } from '@/components'; import { useCustomBundle } from '@/hooks/useCustomBundle'; -import { getFilePackageType } from '@/routes/app/cluster/mods'; import { bindings } from '@/main'; +import { getFilePackageType } from '@/routes/app/cluster/mods'; import { useCommandSuspense } from '@onelauncher/common'; import { createFileRoute } from '@tanstack/react-router'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; @@ -26,8 +26,7 @@ function RouteComponent() { const customBundle = useCustomBundle(bundles, installedPackages, cluster, 'resourcepack'); const allBundles = useMemo(() => - customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, - [filteredBundles, customBundle]); + customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, [filteredBundles, customBundle]); const customTogglePaths = useMemo(() => new Set(['__custom__']), []); diff --git a/apps/oneclient/frontend/src/routes/app/cluster/shaders.tsx b/apps/oneclient/frontend/src/routes/app/cluster/shaders.tsx index 2cc99efe..69e0baa9 100644 --- a/apps/oneclient/frontend/src/routes/app/cluster/shaders.tsx +++ b/apps/oneclient/frontend/src/routes/app/cluster/shaders.tsx @@ -26,8 +26,7 @@ function RouteComponent() { const customBundle = useCustomBundle(bundles, installedPackages, cluster, 'shader'); const allBundles = useMemo(() => - customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, - [filteredBundles, customBundle]); + customBundle !== null ? [...filteredBundles, customBundle] : filteredBundles, [filteredBundles, customBundle]); const customTogglePaths = useMemo(() => new Set(['__custom__']), []); diff --git a/apps/oneclient/frontend/src/routes/app/index.tsx b/apps/oneclient/frontend/src/routes/app/index.tsx index 4ab80d01..9d19cb93 100644 --- a/apps/oneclient/frontend/src/routes/app/index.tsx +++ b/apps/oneclient/frontend/src/routes/app/index.tsx @@ -16,7 +16,6 @@ import { motion } from 'motion/react'; import { Button as AriaButton } from 'react-aria-components'; import { twMerge } from 'tailwind-merge'; - export const Route = createFileRoute('/app/')({ component: RouteComponent, }); @@ -141,15 +140,15 @@ function RecentsCard({
{artSrc ? ( - {`Minecraft - ) + {`Minecraft + ) : ( - - )} + + )}
{artSrc ? ( - - ) + + ) : ( - - )} + + )}
diff --git a/apps/oneclient/frontend/src/routes/app/settings/changelog.tsx b/apps/oneclient/frontend/src/routes/app/settings/changelog.tsx index 4213d3d1..1d9a8000 100644 --- a/apps/oneclient/frontend/src/routes/app/settings/changelog.tsx +++ b/apps/oneclient/frontend/src/routes/app/settings/changelog.tsx @@ -36,8 +36,8 @@ function VersionDropdown({ version, changes, active, current }: VersionDropdownP {changes.length > 0 ? (
    - {changes.map((change, index) => ( -
  • + {changes.map(change => ( +
  • {change}
  • ))} @@ -116,7 +116,7 @@ function RouteComponent() { active={groupIndex === 0 ? true : undefined} changes={group.changes} current={group.version === version ? true : undefined} - key={groupIndex} + key={group.version} version={group.version} /> ) diff --git a/apps/oneclient/frontend/src/routes/onboarding/preferences/version.tsx b/apps/oneclient/frontend/src/routes/onboarding/preferences/version.tsx index 3ae6deda..5dbe0a22 100644 --- a/apps/oneclient/frontend/src/routes/onboarding/preferences/version.tsx +++ b/apps/oneclient/frontend/src/routes/onboarding/preferences/version.tsx @@ -64,7 +64,7 @@ function RouteComponent() { ); } -function VersionCard({ cluster, versionData, version, fullVersionName, setSelectedClusters }: { cluster: OnlineCluster; versionData: VersionInfo; version: OnlineClusterEntry; fullVersionName: string; setSelectedClusters: React.Dispatch>> }) { +function VersionCard({ cluster, versionData: _versionData, version, fullVersionName, setSelectedClusters }: { cluster: OnlineCluster; versionData: VersionInfo; version: OnlineClusterEntry; fullVersionName: string; setSelectedClusters: React.Dispatch>> }) { const [isSelected, setSelected] = useState(false); const toggle = () => { setSelected(prev => !prev); diff --git a/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx b/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx index d7bb0982..ff446521 100644 --- a/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx +++ b/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx @@ -10,7 +10,7 @@ import { Button } from '@onelauncher/common/components'; import { createFileRoute } from '@tanstack/react-router'; import { DotsVerticalIcon } from '@untitled-theme/icons-react'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-react'; -import { useImperativeHandle, useMemo, useRef, useState } from 'react'; +import { useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react'; import { Button as AriaButton } from 'react-aria-components'; import { twMerge } from 'tailwind-merge'; @@ -84,18 +84,15 @@ function RouteComponent() { useImperativeHandle(wrappedRef, () => ({ async openDownloadDialog(nextPath?: string) { // Extract overrides from all enabled bundles before downloading mods - for (const [clusterId, bundles] of Object.entries(bundlesPerCluster)) { - for (const bundle of bundles) { - if (bundle.manifest.enabled) { + for (const [clusterId, bundles] of Object.entries(bundlesPerCluster)) + for (const bundle of bundles) + if (bundle.manifest.enabled) try { await bindings.oneclient.extractBundleOverrides(bundle.path, Number(clusterId)); } catch (e) { console.error(`Failed to extract overrides for bundle ${bundle.manifest.name}:`, e); } - } - } - } // Then delegate to the actual mod download dialog downloadModsRef.current?.openDownloadDialog(nextPath); @@ -178,7 +175,7 @@ function ModCategoryCard({ art, fullVersionName, bundle, mods, setMods, clusterI }); }; - const onClickOnMod: onClickOnMod = (file) => { + const onClickOnMod: onClickOnMod = useCallback((file: ModpackFile) => { setMods((prevMods) => { const existingIndex = prevMods.findIndex(m => m.file === file && m.bundleName === bundleName); const nextMods = existingIndex >= 0 @@ -200,7 +197,7 @@ function ModCategoryCard({ art, fullVersionName, bundle, mods, setMods, clusterI return [...hiddenToAdd, ...nextMods]; }); - }; + }, [bundleName, hiddenEnabledFiles, setMods]); const modsForContext = mods.filter(m => !m.file.hidden).map(m => m.file); @@ -208,7 +205,7 @@ function ModCategoryCard({ art, fullVersionName, bundle, mods, setMods, clusterI onClickOnMod, useVerticalGridLayout: true, mods: modsForContext, - }), [modsForContext]); + }), [modsForContext, onClickOnMod]); return ( diff --git a/apps/onelauncher/desktop/src/lib.rs b/apps/onelauncher/desktop/src/lib.rs index 06718675..5e7acfc6 100644 --- a/apps/onelauncher/desktop/src/lib.rs +++ b/apps/onelauncher/desktop/src/lib.rs @@ -50,6 +50,7 @@ async fn initialize_core() -> LauncherResult<()> { } #[tracing::instrument(skip_all)] +#[allow(clippy::large_stack_frames)] async fn initialize_tauri(builder: tauri::Builder) -> LauncherResult { let router = taurpc::Router::new() .export_config( @@ -125,11 +126,11 @@ fn setup_window(handle: &tauri::AppHandle) -> Result<(), Box Result<(), Box(); unsafe { let ns_window = &*ns_window; if let Some(btn) = diff --git a/apps/onelauncher/frontend/src/components/overlay/popups/AccountPopup.tsx b/apps/onelauncher/frontend/src/components/overlay/popups/AccountPopup.tsx index e6aa0c71..e59b3836 100644 --- a/apps/onelauncher/frontend/src/components/overlay/popups/AccountPopup.tsx +++ b/apps/onelauncher/frontend/src/components/overlay/popups/AccountPopup.tsx @@ -32,7 +32,7 @@ function AccountPopup() {
)} - {users.data?.filter(user => user.id !== defaultUser.data?.id).map(user => ( + {users.data.filter(user => user.id !== defaultUser.data?.id).map(user => (
setDefaultUser(user)} diff --git a/apps/onelauncher/frontend/src/hooks/useCluster.tsx b/apps/onelauncher/frontend/src/hooks/useCluster.tsx index 23220181..3d1a3549 100644 --- a/apps/onelauncher/frontend/src/hooks/useCluster.tsx +++ b/apps/onelauncher/frontend/src/hooks/useCluster.tsx @@ -12,7 +12,7 @@ export function useRecentCluster() { const [cluster, setCluster] = useState(); useEffect(() => { - if (!result.data) + if (!result.isSuccess) return; let mostRecentCluster: ClusterModel | undefined; @@ -39,7 +39,7 @@ export function useRecentCluster() { } setCluster(mostRecentCluster); - }, [result.data]); + }, [result.data, result.isSuccess]); return cluster; } @@ -49,10 +49,10 @@ export function useClusters() { const [clusters, setClusters] = useState | undefined>(); useEffect(() => { - if (!result.data) + if (!result.isSuccess) return; setClusters(result.data); - }, [result.data]); + }, [result.data, result.isSuccess]); return clusters; } diff --git a/apps/onelauncher/frontend/src/hooks/useSettings.tsx b/apps/onelauncher/frontend/src/hooks/useSettings.tsx index 927ea61b..1ef4bd77 100644 --- a/apps/onelauncher/frontend/src/hooks/useSettings.tsx +++ b/apps/onelauncher/frontend/src/hooks/useSettings.tsx @@ -52,13 +52,9 @@ export function SettingsProvider({ children }: SettingsProviderProps) { }, []); const saveChangedSettings = useCallback(() => { - if (!settings) - return; - writeQuery.refetch(); - setSettingsChanged(false); - }, [settings, writeQuery]); + }, [writeQuery]); const handleSetSettingsToSave = useCallback((newSettings: Partial | null) => { setSettingsToSave(newSettings); @@ -72,9 +68,9 @@ export function SettingsProvider({ children }: SettingsProviderProps) { const [value, setValue] = useState(initialValue); useEffect(() => { - const didChange = settings?.[name] !== value; + const didChange = settings[name] !== value; - if (didChange && settings) { + if (didChange) { setSettingsToSave(prev => ({ ...prev, [name]: value, @@ -96,9 +92,6 @@ export function SettingsProvider({ children }: SettingsProviderProps) { createSetting, }), [createSetting, handleSetSettingsToSave, saveChangedSettings, settings, settingsChanged, settingsToSave]); - if (settings === undefined) - return null; - return ( {children} diff --git a/apps/onelauncher/frontend/src/routes/app/browser/index.tsx b/apps/onelauncher/frontend/src/routes/app/browser/index.tsx index 4c0d506e..3dae0e40 100644 --- a/apps/onelauncher/frontend/src/routes/app/browser/index.tsx +++ b/apps/onelauncher/frontend/src/routes/app/browser/index.tsx @@ -30,8 +30,8 @@ function Featured() { const [provider, slug] = useMemo<[Provider, string]>(() => ['Modrinth', 'iris'], []); const featuredPackage = usePackageData(provider, slug, {}); const navigate = useNavigate(); - const featuredImageIndex = useMemo(() => featuredPackage.data?.gallery.findIndex(image => image.featured), [featuredPackage.data]); - const [selectedImage, setSelectedImage] = useState(featuredImageIndex ?? 0); + const featuredImageIndex = useMemo(() => featuredPackage.data.gallery.findIndex(image => image.featured), [featuredPackage.data]); + const [selectedImage, setSelectedImage] = useState(featuredImageIndex === -1 ? 0 : featuredImageIndex); return ( @@ -39,10 +39,10 @@ function Featured() {
Featured
- thumbnail + thumbnail
-

{featuredPackage.data?.name}

+

{featuredPackage.data.name}

@@ -51,10 +51,10 @@ function Featured() {
-

{featuredPackage.data?.short_desc}

+

{featuredPackage.data.short_desc}

- {featuredPackage.data?.gallery.map( + {featuredPackage.data.gallery.map( (image, index) => (
- diff --git a/apps/onelauncher/frontend/src/routes/app/browser/package.$provider.$id.tsx b/apps/onelauncher/frontend/src/routes/app/browser/package.$provider.$id.tsx index c8bf9f0f..81f5d6a6 100644 --- a/apps/onelauncher/frontend/src/routes/app/browser/package.$provider.$id.tsx +++ b/apps/onelauncher/frontend/src/routes/app/browser/package.$provider.$id.tsx @@ -51,7 +51,7 @@ function RouteComponent() { if (!includes(PROVIDERS, provider)) throw new Error('Invalid provider'); const packageData = usePackageData(provider, id, {}); - const { data: packageBody } = useCommand('getPackageBody', () => bindings.core.getPackageBody(provider, packageData.data?.body ?? { Raw: 'No Package Data' })); + const { data: packageBody } = useCommand('getPackageBody', () => bindings.core.getPackageBody(provider, packageData.data.body)); const packageContextValue = useMemo(() => ({ pkg: packageData.data, }), [packageData.data]); @@ -66,7 +66,7 @@ function RouteComponent() { About Versions - Gallery + Gallery
@@ -86,7 +86,7 @@ function RouteComponent() { - {packageData.data?.gallery.map(item => ( + {packageData.data.gallery.map(item => (
@@ -255,7 +255,7 @@ function InstallButton() { limit: 1, }); const version = useMemo(() => { - if (!versions || !browserContext.cluster) + if (!browserContext.cluster) return undefined; return versions.items[0]; }, [browserContext.cluster, versions]); @@ -294,7 +294,7 @@ function InstallButton() { {browserContext.cluster.name} ) - : versionsLoading ? 'Looking for a version...' : 'No matching version found' + : 'No matching version found' : (clusters?.length ?? 0) > 0 ? 'Select a Cluster' : 'No clusters'} @@ -413,8 +413,8 @@ function Versions() { }); const pagination = usePagination({ - itemsCount: versions?.total as unknown as number, - itemsPerPage: versions?.limit as unknown as number, + itemsCount: versions.total as unknown as number, + itemsPerPage: versions.limit as unknown as number, }); const paginationRef = useRef(pagination); useEffect(() => { @@ -422,7 +422,7 @@ function Versions() { }, [pagination.offset]); useEffect(() => { paginationRef.current.reset(); - }, [versions?.total]); + }, [versions.total]); return (
@@ -439,7 +439,7 @@ function Versions() { - {versions?.items.map(item => + {versions.items.map(item => )} diff --git a/apps/onelauncher/frontend/src/routes/app/browser/route.tsx b/apps/onelauncher/frontend/src/routes/app/browser/route.tsx index de748198..af6ccc2f 100644 --- a/apps/onelauncher/frontend/src/routes/app/browser/route.tsx +++ b/apps/onelauncher/frontend/src/routes/app/browser/route.tsx @@ -65,8 +65,6 @@ const defaultFilters: Filters = { package_type: null, }; -type CategoryFilter = Partial>; - function BrowserCategories() { const context = useBrowserContext(); const categoryName = useMemo(() => categoryNameFromId[context.query.filters?.package_type ?? 'mod'], [context.query.filters]); diff --git a/apps/onelauncher/frontend/src/routes/app/browser/search.tsx b/apps/onelauncher/frontend/src/routes/app/browser/search.tsx index f003494b..082d69ef 100644 --- a/apps/onelauncher/frontend/src/routes/app/browser/search.tsx +++ b/apps/onelauncher/frontend/src/routes/app/browser/search.tsx @@ -32,11 +32,7 @@ function Search() { return ( <> - { - search.data - ? - :

Loading

- } + ); } diff --git a/apps/onelauncher/frontend/src/routes/app/cluster/screenshots.tsx b/apps/onelauncher/frontend/src/routes/app/cluster/screenshots.tsx index 565ac24e..a70cc598 100644 --- a/apps/onelauncher/frontend/src/routes/app/cluster/screenshots.tsx +++ b/apps/onelauncher/frontend/src/routes/app/cluster/screenshots.tsx @@ -27,10 +27,10 @@ function RouteComponent() { No screenshots found. Press F2 in game to take a screenshot!
} // @ts-ignore idk - when={result.data?.length > 0} + when={result.data.length > 0} >
- {result.data?.map(data => ( + {result.data.map(data => ( ))}
diff --git a/apps/onelauncher/frontend/src/routes/app/cluster/settings.tsx b/apps/onelauncher/frontend/src/routes/app/cluster/settings.tsx index 86dfeece..9843f1c6 100644 --- a/apps/onelauncher/frontend/src/routes/app/cluster/settings.tsx +++ b/apps/onelauncher/frontend/src/routes/app/cluster/settings.tsx @@ -27,18 +27,15 @@ function RouteComponent() { save.refetch(); }); - if (_result.isPending) - return

loading...

; - return (

Minecraft Settings

- + - +
diff --git a/apps/onelauncher/frontend/src/routes/app/cluster/worlds.tsx b/apps/onelauncher/frontend/src/routes/app/cluster/worlds.tsx index 00040da9..6e051f9a 100644 --- a/apps/onelauncher/frontend/src/routes/app/cluster/worlds.tsx +++ b/apps/onelauncher/frontend/src/routes/app/cluster/worlds.tsx @@ -23,10 +23,10 @@ function RouteComponent() {
No worlds found.
} - when={list.data !== undefined && list.data.length > 0} + when={list.data.length > 0} >
- {list.data?.map(data => ( + {list.data.map(data => ( ))}
diff --git a/apps/onelauncher/frontend/src/routes/app/index.tsx b/apps/onelauncher/frontend/src/routes/app/index.tsx index 82b0cceb..b279b270 100644 --- a/apps/onelauncher/frontend/src/routes/app/index.tsx +++ b/apps/onelauncher/frontend/src/routes/app/index.tsx @@ -171,9 +171,6 @@ function ClusterCard({ const handleLaunch = () => { launch.mutate(); - - if (launch.error) - console.error(launch.error.message); }; const image = () => { diff --git a/apps/onelauncher/frontend/src/routes/app/settings/accounts.tsx b/apps/onelauncher/frontend/src/routes/app/settings/accounts.tsx index da500e3e..3db1b7c8 100644 --- a/apps/onelauncher/frontend/src/routes/app/settings/accounts.tsx +++ b/apps/onelauncher/frontend/src/routes/app/settings/accounts.tsx @@ -18,29 +18,21 @@ interface Account { } function RouteComponent() { - const { data: usersData, isLoading: usersLoading } = useCommand('getUsers', bindings.core.getUsers); - const { data: defaultUserData, isLoading: defaultUserLoading } = useCommand('getDefaultUser', () => bindings.core.getDefaultUser(false)); + const { data: usersData } = useCommand('getUsers', bindings.core.getUsers); + const { data: defaultUserData } = useCommand('getDefaultUser', () => bindings.core.getDefaultUser(false)); const addAccount = useCommand('openMsaLogin', bindings.core.openMsaLogin, { enabled: false, subscribed: false, }); - if (usersLoading || defaultUserLoading) - return ( - -

Accounts

-

Loading accounts...

-
- ); - return (

Accounts

- No accounts found.

} when={usersData && usersData.length > 0}> - {usersData?.map(account => ( + No accounts found.

} when={usersData.length > 0}> + {usersData.map(account => ( LauncherResult<()> { println!("Credentials: {creds:#?}"); Ok(()) -} \ No newline at end of file +} diff --git a/packages/core/examples/dirs.rs b/packages/core/examples/dirs.rs index b58ed72c..9769c7e1 100644 --- a/packages/core/examples/dirs.rs +++ b/packages/core/examples/dirs.rs @@ -2,11 +2,13 @@ use onelauncher_core::store::{Core, CoreOptions, Dirs}; #[tokio::main] async fn main() { - Core::initialize(CoreOptions::default()).await.expect("couldn't initialize core"); + Core::initialize(CoreOptions::default()) + .await + .expect("couldn't initialize core"); let dirs = Dirs::get().await.expect("couldn't initialize dirs"); println!(" Base dir : {}", dirs.base_dir().display()); println!("Launcher logs dir : {}", dirs.launcher_logs_dir().display()); println!(" Metadata dir : {}", dirs.metadata_dir().display()); println!(" DB file : {}", dirs.db_file().display()); -} \ No newline at end of file +} diff --git a/packages/core/examples/discord.rs b/packages/core/examples/discord.rs index 28c70bef..33a5fa32 100644 --- a/packages/core/examples/discord.rs +++ b/packages/core/examples/discord.rs @@ -1,15 +1,23 @@ use discord_rich_presence::activity::Timestamps; -use onelauncher_core::{api::proxy::ProxyEmpty, error::LauncherResult, initialize_core, store::{CoreOptions, State}}; +use onelauncher_core::api::proxy::ProxyEmpty; +use onelauncher_core::error::LauncherResult; +use onelauncher_core::initialize_core; +use onelauncher_core::store::{CoreOptions, State}; #[tokio::main] async fn main() -> LauncherResult<()> { - initialize_core(CoreOptions { - discord_client_id: Some(String::from("1274084193193955408")), - ..Default::default() - }, ProxyEmpty::new()).await?; + initialize_core( + CoreOptions { + discord_client_id: Some(String::from("1274084193193955408")), + ..Default::default() + }, + ProxyEmpty::new(), + ) + .await?; let state = State::get().await?; - let Some(rpc) = &state.rpc else { + let rpc_lock = state.rpc.read().await; + let Some(rpc) = &*rpc_lock else { println!("RPC is not initialized"); return Ok(()); }; @@ -18,11 +26,13 @@ async fn main() -> LauncherResult<()> { println!("Set Discord message"); tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - rpc.set_message("New timestamp.", Some(Timestamps::new())).await; + rpc.set_message("New timestamp.", Some(Timestamps::new())) + .await; println!("Set Discord message"); tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - rpc.set_message("Reverted back to the old timestamp!", None).await; + rpc.set_message("Reverted back to the old timestamp!", None) + .await; println!("Set Discord message"); tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; @@ -30,4 +40,4 @@ async fn main() -> LauncherResult<()> { println!("Cleared Discord message"); Ok(()) -} \ No newline at end of file +} diff --git a/packages/core/examples/download_java.rs b/packages/core/examples/download_java.rs index 6bdc1a9e..144e0b45 100644 --- a/packages/core/examples/download_java.rs +++ b/packages/core/examples/download_java.rs @@ -20,7 +20,7 @@ async fn main() -> LauncherResult<()> { let path = java::install_java_package(pkg).await?; - println!("java package installed at '{path:?}'"); + println!("java package installed at '{}'", path.display()); Ok(()) } diff --git a/packages/core/examples/launch.rs b/packages/core/examples/launch.rs index 7614e7ac..76e2fa9a 100644 --- a/packages/core/examples/launch.rs +++ b/packages/core/examples/launch.rs @@ -35,7 +35,10 @@ pub async fn main() -> LauncherResult<()> { // We create a settings profile so that we can run hooks let profile_name = "profile with hooks example"; - if setting_profiles::dao::get_profile_by_name(profile_name).await?.is_none() { + if setting_profiles::dao::get_profile_by_name(profile_name) + .await? + .is_none() + { setting_profiles::create_profile(profile_name, async |mut profile| { profile.hook_pre = Set(Some("echo this is a pre-hook!".to_string())); profile.hook_post = Set(Some("echo this is my post-hook!".to_string())); @@ -46,14 +49,17 @@ pub async fn main() -> LauncherResult<()> { } Ok(profile) - }).await?; + }) + .await?; } // Here we create the cluster let cluster_name = "Launchable"; let path = dirs.clusters_dir().join(cluster_name); - let mut cluster = if let Some(cluster) = api::cluster::dao::get_cluster_by_folder_name(&path).await? { + let mut cluster = if let Some(cluster) = + api::cluster::dao::get_cluster_by_folder_name(&path).await? + { cluster } else { api::cluster::create_cluster(cluster_name, "1.20.4", GameLoader::Fabric, None, None).await? @@ -64,12 +70,16 @@ pub async fn main() -> LauncherResult<()> { cluster.setting_profile_name = Set(Some(profile_name.to_string())); Ok(cluster) - }).await?; + }) + .await?; - println!("Using cluster: {} at '{}'", cluster.name, cluster.folder_name); + println!( + "Using cluster: {} at '{}'", + cluster.name, cluster.folder_name + ); // Launch the game - let process = api::game::launch::launch_minecraft(&mut cluster, creds, None).await?; + let process = api::game::launch::launch_minecraft(&mut cluster, creds, None, None).await?; println!("Process: {:?}", process.read().await); // We wait for the process to finish so that we can run code after diff --git a/packages/core/examples/locate_java.rs b/packages/core/examples/locate_java.rs index 4c17bd09..76da067a 100644 --- a/packages/core/examples/locate_java.rs +++ b/packages/core/examples/locate_java.rs @@ -1,4 +1,8 @@ -use onelauncher_core::{api::{java, proxy::ProxyEmpty}, error::LauncherResult, initialize_core, store::CoreOptions}; +use onelauncher_core::api::java; +use onelauncher_core::api::proxy::ProxyEmpty; +use onelauncher_core::error::LauncherResult; +use onelauncher_core::initialize_core; +use onelauncher_core::store::CoreOptions; #[tokio::main] async fn main() -> LauncherResult<()> { @@ -12,4 +16,4 @@ async fn main() -> LauncherResult<()> { } Ok(()) -} \ No newline at end of file +} diff --git a/packages/core/examples/metadata.rs b/packages/core/examples/metadata.rs index 47fbd5f7..7e72c4b7 100644 --- a/packages/core/examples/metadata.rs +++ b/packages/core/examples/metadata.rs @@ -1,4 +1,7 @@ -use onelauncher_core::{api::proxy::ProxyDynamic, error::LauncherResult, initialize_core, store::{CoreOptions, State}}; +use onelauncher_core::api::proxy::ProxyDynamic; +use onelauncher_core::error::LauncherResult; +use onelauncher_core::initialize_core; +use onelauncher_core::store::{CoreOptions, State}; use onelauncher_entity::loader::GameLoader; #[tokio::main] @@ -9,12 +12,39 @@ async fn main() -> LauncherResult<()> { let metadata = &mut state.metadata.write().await; println!("Initialized: {}", metadata.initialized()); - println!("Minecraft: {:?}", metadata.get_vanilla_or_fetch().await.is_ok()); - println!("Forge: {:?}", metadata.get_modded_or_fetch(&GameLoader::Forge).await.is_ok()); + println!( + "Minecraft: {:?}", + metadata.get_vanilla_or_fetch().await.is_ok() + ); + println!( + "Forge: {:?}", + metadata + .get_modded_or_fetch(&GameLoader::Forge) + .await + .is_ok() + ); println!("Initialized: {}", metadata.initialized()); - println!("NeoForge: {:?}", metadata.get_modded_or_fetch(&GameLoader::NeoForge).await.is_ok()); - println!("Fabric: {:?}", metadata.get_modded_or_fetch(&GameLoader::Fabric).await.is_ok()); - println!("Quilt: {:?}", metadata.get_modded_or_fetch(&GameLoader::Quilt).await.is_ok()); + println!( + "NeoForge: {:?}", + metadata + .get_modded_or_fetch(&GameLoader::NeoForge) + .await + .is_ok() + ); + println!( + "Fabric: {:?}", + metadata + .get_modded_or_fetch(&GameLoader::Fabric) + .await + .is_ok() + ); + println!( + "Quilt: {:?}", + metadata + .get_modded_or_fetch(&GameLoader::Quilt) + .await + .is_ok() + ); Ok(()) -} \ No newline at end of file +} diff --git a/packages/core/src/api/cluster/content.rs b/packages/core/src/api/cluster/content.rs index 69e02a21..bdeb2f7b 100644 --- a/packages/core/src/api/cluster/content.rs +++ b/packages/core/src/api/cluster/content.rs @@ -105,7 +105,10 @@ pub async fn get_log_by_name( return Ok(None); } - let content = if file_name.ends_with(".gz") { + let content = if std::path::Path::new(file_name) + .extension() + .is_some_and(|ext| ext.eq_ignore_ascii_case("gz")) + { io::read_gz_to_string(&path).await? } else { io::read_to_string(&path).await? @@ -136,6 +139,7 @@ pub async fn get_process_log_tail( Ok(Some(tail)) } +#[allow(clippy::cast_possible_truncation, clippy::naive_bytecount)] async fn read_process_log_tail( path: &Path, max_lines: usize, @@ -174,12 +178,10 @@ async fn read_process_log_tail( file.read_exact(&mut chunk).await?; newline_count += chunk.iter().filter(|byte| **byte == b'\n').count(); - if buffer.is_empty() { - buffer = chunk; - } else { + if !buffer.is_empty() { chunk.extend_from_slice(&buffer); - buffer = chunk; } + buffer = chunk; } let raw = String::from_utf8_lossy(&buffer); diff --git a/packages/core/src/api/cluster/mod.rs b/packages/core/src/api/cluster/mod.rs index 3d886f9b..dc70cbf0 100644 --- a/packages/core/src/api/cluster/mod.rs +++ b/packages/core/src/api/cluster/mod.rs @@ -187,7 +187,7 @@ async fn install_cluster( let version = versions_list[version_index].clone(); - let minecraft_updated = metadata::is_version_updated(version_index, &versions_list); + let minecraft_updated = metadata::is_version_updated(version_index, versions_list); drop(metadata); diff --git a/packages/core/src/api/cluster/sync.rs b/packages/core/src/api/cluster/sync.rs index e333f980..019d6ad9 100644 --- a/packages/core/src/api/cluster/sync.rs +++ b/packages/core/src/api/cluster/sync.rs @@ -118,8 +118,7 @@ pub async fn sync_cluster(cluster: &clusters::Model) -> LauncherResult