diff --git a/package.json b/package.json index 9e88073..21add9a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "liquidlauncher", "private": true, - "version": "0.2.2", + "version": "0.2.4", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 14bd245..8d429c2 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -294,7 +294,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "azalea-auth" version = "0.9.0" -source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#2b7484af0dd7bde6d68a7395f59d41e98ba7f2dc" +source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#86c165e8faf7db778b7c36bd17283445be6156dc" dependencies = [ "azalea-buf", "azalea-crypto", @@ -316,7 +316,7 @@ dependencies = [ [[package]] name = "azalea-buf" version = "0.9.0" -source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#2b7484af0dd7bde6d68a7395f59d41e98ba7f2dc" +source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#86c165e8faf7db778b7c36bd17283445be6156dc" dependencies = [ "azalea-buf-macros", "byteorder", @@ -329,7 +329,7 @@ dependencies = [ [[package]] name = "azalea-buf-macros" version = "0.9.0" -source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#2b7484af0dd7bde6d68a7395f59d41e98ba7f2dc" +source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#86c165e8faf7db778b7c36bd17283445be6156dc" dependencies = [ "proc-macro2", "quote", @@ -339,7 +339,7 @@ dependencies = [ [[package]] name = "azalea-crypto" version = "0.9.0" -source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#2b7484af0dd7bde6d68a7395f59d41e98ba7f2dc" +source = "git+https://github.com/CCBlueX/azalea.git?branch=custom_auth#86c165e8faf7db778b7c36bd17283445be6156dc" dependencies = [ "aes", "azalea-buf", @@ -355,9 +355,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "95d8e92cac0961e91dbd517496b00f7e9b92363dbe6d42c3198268323798860c" dependencies = [ "addr2line", "cc", @@ -557,9 +557,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -2370,7 +2370,7 @@ checksum = "f0b5399f6804fbab912acbd8878ed3532d506b7c951b8f9f164ef90fef39e3f4" [[package]] name = "liquidlauncher" -version = "0.2.2" +version = "0.2.4" dependencies = [ "anyhow", "async-compression", @@ -4199,9 +4199,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -4509,9 +4509,9 @@ checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" [[package]] name = "tauri" -version = "2.0.0-beta.12" +version = "2.0.0-beta.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33d0026c6146b73322833bc8e51fc4ee400a814c4cbfe489e3c2aa92cfedcec" +checksum = "3b119a486a9075ae20bfb8ed9a1883aff862c61a9c1cb1ef1336620536f032cc" dependencies = [ "anyhow", "bytes", @@ -4637,9 +4637,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.0.0-beta.2" +version = "2.0.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c7894fb904ed003fd15915b263655672be4e4581298f7fa8916016e50010ed" +checksum = "462456015607e4325d39dbb74e53f5a3cdcec3074b08ba8ce4936f7f936f8833" dependencies = [ "glib 0.16.9", "log", @@ -4655,9 +4655,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.0.0-beta.2" +version = "2.0.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d71f69535111078131380bcf2a4c2f190ef4d045a33d787a606e7d4fc6a786" +checksum = "31961707e3be23c95f5fe39cb7688217e3c571a9a88aa9a03149b56bffd8036c" dependencies = [ "anyhow", "glob", @@ -4674,9 +4674,9 @@ dependencies = [ [[package]] name = "tauri-plugin-process" -version = "2.0.0-beta.2" +version = "2.0.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e3a9a8fcce829133941bbd2f164114cf7feb012a6c06a8c4b7e531a8dcd01d" +checksum = "11215c3615299090e97f37341ae4b01f518bc1d43e9c4391144c0e5e3b7d4f01" dependencies = [ "tauri", "tauri-plugin", @@ -4684,9 +4684,9 @@ dependencies = [ [[package]] name = "tauri-plugin-shell" -version = "2.0.0-beta.2" +version = "2.0.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e5c2d4187bc552d1be72081588c34187eb29e4c375cdfe99872f8d57b6aead" +checksum = "5624537650f627707f3bd9c6562efe2116c7fb043fcfc2e3d10f802d7870a1cd" dependencies = [ "encoding_rs", "log", @@ -4704,9 +4704,9 @@ dependencies = [ [[package]] name = "tauri-plugin-updater" -version = "2.0.0-beta.2" +version = "2.0.0-beta.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb1f95a0fa908434f19241137255ad84bc9433b4b5ce6727f26f6b22a74622e" +checksum = "106ed17da7442061bf3c0577cd22091424d1a64c86569064e99e7466d97dca65" dependencies = [ "base64 0.21.7", "dirs-next", @@ -4727,6 +4727,7 @@ dependencies = [ "time", "tokio", "url", + "windows-sys 0.52.0", "zip", ] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 0d165e1..44e3851 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "liquidlauncher" -version = "0.2.2" +version = "0.2.4" description = "A LiquidBounce launcher for Minecraft, written in Rust using Tauri." authors = ["1zuna ", "superblaubeere27"] license = "GNU General Public License v3.0" diff --git a/src-tauri/capabilities/main.json b/src-tauri/capabilities/main.json index 8cde81a..02fcfc6 100644 --- a/src-tauri/capabilities/main.json +++ b/src-tauri/capabilities/main.json @@ -17,6 +17,7 @@ "dialog:allow-message", "dialog:allow-open", "dialog:allow-confirm", + "dialog:allow-ask", "shell:allow-open", "process:allow-exit", "updater:default" diff --git a/src-tauri/src/app/gui.rs b/src-tauri/src/app/gui.rs index 6da613d..6f5d001 100644 --- a/src-tauri/src/app/gui.rs +++ b/src-tauri/src/app/gui.rs @@ -19,6 +19,7 @@ use std::{sync::{Arc, Mutex}, thread, path::PathBuf}; +use anyhow::anyhow; use tokio::fs; use tracing::{error, info, debug}; use tauri::{Manager, Window}; @@ -38,13 +39,25 @@ struct AppState { runner_instance: Arc>> } +const ERROR_MSG: &str = "Try restarting the LiquidLauncher with administrator rights.\nIf this error persists, upload your log with the button below and report it to GitHub."; + #[tauri::command] async fn get_launcher_version() -> Result { Ok(LAUNCHER_VERSION.to_string()) } #[tauri::command] -async fn check_online_status() -> Result<(), String> { +async fn check_health() -> Result<(), String> { + // Check hosts + #[cfg(windows)] + { + use crate::utils::check_hosts_file; + + info!("Checking hosts file..."); + check_hosts_file().await + .map_err(|e| format!("{}", e))?; + } + info!("Checking online status"); HTTP_CLIENT.get("https://api.liquidbounce.net/") .send().await @@ -118,7 +131,7 @@ async fn login_microsoft(window: tauri::Window) -> Result Re Ok(()) } +pub fn log(window: &Arc>, msg: &str) { + info!("{}", msg); + + if let Ok(k) = window.lock() { + let _ = k.emit("process-output", msg); + } +} + fn handle_stdout(window: &Arc>, data: &[u8]) -> anyhow::Result<()> { let data = String::from_utf8(data.to_vec())?; if data.is_empty() { @@ -198,7 +219,7 @@ fn handle_stdout(window: &Arc>, data: &[u8]) -> anyhow: } info!("{}", data); - window.lock().unwrap().emit("process-output", data)?; + window.lock().map_err(|_| anyhow!("Window lock is poisoned"))?.emit("process-output", data)?; Ok(()) } @@ -209,12 +230,12 @@ fn handle_stderr(window: &Arc>, data: &[u8]) -> anyhow: } error!("{}", data); - window.lock().unwrap().emit("process-output", data)?; + window.lock().map_err(|_| anyhow!("Window lock is poisoned"))?.emit("process-output", data)?; Ok(()) } fn handle_progress(window: &Arc>, progress_update: ProgressUpdate) -> anyhow::Result<()> { - window.lock().unwrap().emit("progress-update", progress_update)?; + window.lock().map_err(|_| anyhow!("Window lock is poisoned"))?.emit("progress-update", progress_update)?; Ok(()) } @@ -289,7 +310,7 @@ async fn run_client(build_id: u32, account_data: MinecraftAccount, options: Laun } let message = format!("An error occourd:\n\n{:?}", e); - window_mutex.lock().unwrap().emit("client-error", format!("{}\n\nIf this error persists, upload your log with the button below and report it to GitHub.", message)).unwrap(); + window_mutex.lock().unwrap().emit("client-error", format!("{}\n\n{}", message, ERROR_MSG)).unwrap(); handle_stderr(&window_mutex, message.as_bytes()).unwrap(); }; @@ -386,7 +407,7 @@ pub fn gui_main() { runner_instance: Arc::new(Mutex::new(None)) }) .invoke_handler(tauri::generate_handler![ - check_online_status, + check_health, get_options, store_options, request_branches, diff --git a/src-tauri/src/app/webview.rs b/src-tauri/src/app/webview.rs index 3fc7116..0469372 100644 --- a/src-tauri/src/app/webview.rs +++ b/src-tauri/src/app/webview.rs @@ -17,33 +17,85 @@ * along with LiquidLauncher. If not, see . */ -use std::{sync::{Arc, Mutex}, time::Duration}; +use std::{sync::{atomic::{AtomicBool, Ordering}, Arc, Mutex}, time::Duration}; use serde::Deserialize; -use anyhow::{Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use tracing::{info, debug}; -use tauri::{Manager, WebviewUrl, WebviewWindowBuilder}; +use tauri::{Manager, Url, WebviewUrl, WebviewWindowBuilder}; use tokio::time::sleep; -use crate::utils::download_file; - -pub(crate) async fn download_client(url: &str, on_progress: F, window: &Arc>) -> Result> where F : Fn(u64, u64){ - let download_page = format!("{}&liquidlauncher=1", url); - let download_view = WebviewWindowBuilder::new( - window.lock().unwrap().app_handle(), - "download_view", - WebviewUrl::External(download_page.parse().unwrap()) - ).title("Download of LiquidBounce") - .center() - .focused(true) - .maximized(true) - .build().unwrap(); +use crate::minecraft::progress::{ProgressReceiver, ProgressUpdate}; + +use super::gui::log; + +const MAX_DOWNLOAD_ATTEMPTS: u8 = 5; + +pub async fn open_download_page(url: &str, on_progress: &impl ProgressReceiver, window: &Arc>) -> Result { + let download_page: Url = format!("{}&liquidlauncher=1", url).parse() + .context("Failed to parse download page URL")?; + + let mut count = 0; + + let url = loop { + count += 1; + + if count > MAX_DOWNLOAD_ATTEMPTS { + bail!("Failed to open download page after {} attempts", MAX_DOWNLOAD_ATTEMPTS); + } + + log(&window, &format!("Opening download page... (Attempt {}/{})", count, MAX_DOWNLOAD_ATTEMPTS)); + on_progress.progress_update(ProgressUpdate::SetLabel(format!("Opening download page... (Attempt {}/{})", count, MAX_DOWNLOAD_ATTEMPTS))); + + match show_webview(download_page.clone(), window).await { + Ok(url) => break url, + Err(e) => { + log(&window, &format!("Failed to open download page: {:?}", e)); + sleep(Duration::from_millis(500)).await; + } + } + }; + + Ok(url) +} + +async fn show_webview(url: Url, window: &Arc>) -> Result { + // Find download_view window from the window manager + let mut download_view = { + let window = window.lock() + .map_err(|_| anyhow!("Failed to lock window"))?; + + match window.get_webview_window("download_view") { + Some(window) => Ok(window), + None => { + // todo: do not hardcode index + let config = window.config().app.windows.get(1) + .context("Unable to find window config")?; + + WebviewWindowBuilder::from_config(window.app_handle(), config) + .map_err(|e| anyhow!("Failed to build window: {:?}", e))? + .build() + }, + } + }?; + + // Redirect the download view to the download page + download_view.navigate(url); // Show and maximize the download view - download_view.show().unwrap(); - download_view.maximize().unwrap(); + download_view.show() + .context("Failed to show the download view")?; // Wait for the download to finish let download_link_cell = Arc::new(Mutex::new(None)); + let close_request = Arc::new(AtomicBool::new(false)); + let cloned_close_request = close_request.clone(); let cloned_cell = download_link_cell.clone(); + + download_view.on_window_event(move |event| { + if let tauri::WindowEvent::CloseRequested { api, .. } = event { + api.prevent_close(); + close_request.store(true, Ordering::SeqCst); + } + }); download_view.once("download", move |event| { debug!("Download Event received: {:?}", event); @@ -65,19 +117,23 @@ pub(crate) async fn download_client(url: &str, on_progress: F, window: &Arc(data: &Path, manifest: LaunchManifest, versi let launcher_data_arc = Arc::new(launcher_data); let features: HashSet = HashSet::new(); - - info!("Determined OS to be {} {}", OS, OS_VERSION.clone()); + log(&window, &format!("Determined OS to be {} {}", OS, OS_VERSION.clone())); // JRE download let runtimes_folder = data.join("runtimes"); @@ -73,15 +73,15 @@ pub async fn launch(data: &Path, manifest: LaunchManifest, versi let java_bin = match &launching_parameter.custom_java_path { Some(path) => PathBuf::from(path), None => { - info!("Checking for JRE..."); + log(&window, "Checking for JRE..."); launcher_data_arc.progress_update(ProgressUpdate::set_label("Checking for JRE...")); match find_java_binary(&runtimes_folder, &manifest.build.jre_distribution, &*manifest.build.jre_version.to_string()).await { Ok(jre) => jre, Err(e) => { - error!("Failed to find JRE: {}", e); + log(&window, &format!("Failed to find JRE: {}", e)); - info!("Download JRE..."); + log(&window, "Downloading JRE..."); launcher_data_arc.progress_update(ProgressUpdate::set_label("Download JRE...")); jre_downloader::jre_download(&runtimes_folder, &manifest.build.jre_distribution, &*manifest.build.jre_version.to_string(), |a, b| { launcher_data_arc.progress_update(ProgressUpdate::set_for_step(ProgressUpdateSteps::DownloadJRE, get_progress(0, a, b), get_max(1))); @@ -90,8 +90,8 @@ pub async fn launch(data: &Path, manifest: LaunchManifest, versi } } }; - - debug!("Java binary: {}", java_bin.to_str().unwrap()); + + log(&window, &format!("Java binary: {:?}", java_bin)); if !java_bin.exists() { bail!("Java binary not found"); } @@ -299,6 +299,7 @@ pub async fn launch(data: &Path, manifest: LaunchManifest, versi launcher_data_arc.progress_update(ProgressUpdate::set_label("Launching...")); launcher_data_arc.progress_update(ProgressUpdate::set_to_max()); + log(&window, "Launching..."); let mut running_task = java_runtime.execute(mapped, &game_dir).await?; @@ -306,11 +307,15 @@ pub async fn launch(data: &Path, manifest: LaunchManifest, versi if !launching_parameter.keep_launcher_open { // Hide launcher window - window.lock().unwrap().hide().unwrap(); + if let Err(err) = window.lock() + .map_err(|_| anyhow!("Unable to lock window due to poisoned mutex"))? + .hide() { + error!("Failed to hide window: {}", err); + } } - + let launcher_data = Arc::try_unwrap(launcher_data_arc) - .unwrap_or_else(|_| panic!()); + .map_err(|_| anyhow!("Failed to unwrap launcher data"))?; let terminator = launcher_data.terminator; let data = launcher_data.data; diff --git a/src-tauri/src/minecraft/prelauncher.rs b/src-tauri/src/minecraft/prelauncher.rs index b3524fb..4e8e4ec 100644 --- a/src-tauri/src/minecraft/prelauncher.rs +++ b/src-tauri/src/minecraft/prelauncher.rs @@ -27,8 +27,9 @@ use tokio::fs; use tokio::io::AsyncReadExt; use crate::app::api::{LaunchManifest, LoaderSubsystem, ModSource, LoaderMod}; +use crate::app::gui::log; use crate::error::LauncherError; -use crate::app::webview::download_client; +use crate::app::webview::open_download_page; use crate::LAUNCHER_DIRECTORY; use crate::minecraft::launcher; use crate::minecraft::launcher::{LauncherData, LaunchingParameter}; @@ -40,16 +41,7 @@ use crate::utils::{download_file, get_maven_artifact_path}; /// Prelaunching client /// pub(crate) async fn launch(launch_manifest: LaunchManifest, launching_parameter: LaunchingParameter, additional_mods: Vec, progress: LauncherData, window: Arc>) -> Result<()> { - // Check hosts - #[cfg(windows)] - { - use crate::utils::check_hosts_file; - - info!("Checking hosts file..."); - check_hosts_file(&window).await?; - } - - info!("Loading minecraft version manifest..."); + log(&window, "Loading minecraft version manifest..."); let mc_version_manifest = VersionManifest::fetch().await?; let build = &launch_manifest.build; @@ -68,7 +60,7 @@ pub(crate) async fn launch(launch_manifest: LaunchManifest, laun retrieve_and_copy_mods(&data_directory, &launch_manifest, &launch_manifest.mods, &progress, &window).await?; retrieve_and_copy_mods(&data_directory, &launch_manifest, &additional_mods, &progress, &window).await?; - info!("Loading version profile..."); + log(&window, "Loading version profile..."); let manifest_url = match subsystem { LoaderSubsystem::Fabric { manifest, .. } => manifest .replace("{MINECRAFT_VERSION}", &build.mc_version) @@ -85,14 +77,14 @@ pub(crate) async fn launch(launch_manifest: LaunchManifest, laun .ok_or_else(|| LauncherError::InvalidVersionProfile(format!("unable to find inherited version manifest {}", inherited_version)))?; debug!("Determined {}'s download url to be {}", inherited_version, url); - info!("Downloading inherited version {}...", inherited_version); + log(&window, &format!("Downloading inherited version {}...", inherited_version)); let parent_version = VersionProfile::load(url).await?; version.merge(parent_version)?; } - info!("Launching {}...", launch_manifest.build.commit_id); + log(&window, &format!("Launching {}...", launch_manifest.build.commit_id)); launcher::launch(&data_directory, launch_manifest, version, launching_parameter, progress, window).await?; Ok(()) } @@ -143,6 +135,7 @@ pub async fn retrieve_and_copy_mods(data: &Path, manifest: &LaunchManifest, mods fs::copy(mod_custom_path.join(file_name), mods_path.join(file_name)) .await .with_context(|| format!("Failed to copy custom mod {}", current_mod.name))?; + log(&window, &format!("Copied custom mod {}", current_mod.name)); progress.progress_update(ProgressUpdate::set_label(format!("Copied custom mod {}", current_mod.name))); continue; } @@ -158,7 +151,13 @@ pub async fn retrieve_and_copy_mods(data: &Path, manifest: &LaunchManifest, mods let contents = match ¤t_mod.source { ModSource::SkipAd { artifact_name: _, url, extract } => { - let retrieved_bytes = download_client(url, |a, b| progress.progress_update(ProgressUpdate::set_for_step(ProgressUpdateSteps::DownloadLiquidBounceMods, get_progress(mod_idx, a, b) as u64, max)), window).await?; + log(&window, &format!("Opening download page for mod {} on {}", current_mod.name, url)); + progress.progress_update(ProgressUpdate::set_label(format!("Opening download page for mod {}", current_mod.name))); + let direct_url = open_download_page(url, progress, window).await?; + + log(&window, &format!("Downloading mod {} from {}", current_mod.name, direct_url)); + progress.progress_update(ProgressUpdate::set_label(format!("Downloading mod {}", current_mod.name))); + let retrieved_bytes = download_file(&direct_url, |a, b| progress.progress_update(ProgressUpdate::set_for_step(ProgressUpdateSteps::DownloadLiquidBounceMods, get_progress(mod_idx, a, b) as u64, max))).await?; // Extract bytes if *extract { @@ -183,7 +182,7 @@ pub async fn retrieve_and_copy_mods(data: &Path, manifest: &LaunchManifest, mods } }, ModSource::Repository { repository, artifact } => { - info!("downloading mod {} from {}", artifact, repository); + log(&window, &format!("Downloading mod {} from {}", artifact, repository)); let repository_url = manifest.repositories.get(repository) .ok_or_else(|| LauncherError::InvalidVersionProfile(format!("There is no repository specified with the name {}", repository)))?; diff --git a/src-tauri/src/utils/extract.rs b/src-tauri/src/utils/extract.rs index 655cb32..3a05895 100644 --- a/src-tauri/src/utils/extract.rs +++ b/src-tauri/src/utils/extract.rs @@ -18,7 +18,7 @@ */ use anyhow::{Result, Context}; -use std::{path::{Path, PathBuf}}; +use std::path::{Path, PathBuf}; use async_compression::tokio::bufread::GzipDecoder; use async_zip::read::seek::ZipFileReader; use tokio::fs::{create_dir_all, OpenOptions}; diff --git a/src-tauri/src/utils/hosts.rs b/src-tauri/src/utils/hosts.rs index 683aa1e..8baff3d 100644 --- a/src-tauri/src/utils/hosts.rs +++ b/src-tauri/src/utils/hosts.rs @@ -1,16 +1,30 @@ -use std::sync::{Arc, Mutex}; +use std::env; -use anyhow::{bail, Result}; -use tauri_plugin_shell::ShellExt; +use anyhow::{bail, Context, Result}; +use tokio::fs; -const HOSTS_PATH: &str = "C:\\Windows\\System32\\drivers\\etc\\hosts"; +const HOSTS_PATH: &str = "Windows\\System32\\drivers\\etc\\hosts"; +const HOSTS: [&str; 4] = ["mojang.com", "minecraft.net", "liquidbounce.net", "ccbluex.net"]; /// We have noticed many user have modified the hosts file to block the Minecraft authentication server. /// This is likely by using a third-party program. Because LiquidLauncher requires access to the authentication server, we have to modify the hosts file to allow access. /// we need to check the hosts file and alert the user if it has been modified. -pub async fn check_hosts_file(window: &Arc>) -> Result<()> { +pub async fn check_hosts_file() -> Result<()> { + // Get location of Windows hosts file dynamically + // "SystemDrive" env, if not assigned default to C: + let system_drive = env::var("SystemDrive").unwrap_or("C:".to_string()); + let hosts_path = format!("{}\\{}", system_drive, HOSTS_PATH); + + // Check if hosts file exists, if not cancel this check with OK + if let Ok(exists) = fs::try_exists(&hosts_path).await { + if !exists { + return Ok(()); + } + } + // Check if the hosts file has been modified - let hosts_file = tokio::fs::read_to_string(HOSTS_PATH).await?; + let hosts_file = fs::read_to_string(&hosts_path).await + .context(format!("Failed to read hosts file at {}", hosts_path))?; let flagged_entries = hosts_file.lines() .filter(|line| { @@ -27,16 +41,12 @@ pub async fn check_hosts_file(window: &Arc>) -> Result<()> Some(domain) => domain, None => return false, }; - - domain.contains("mojang.com") || domain.contains("minecraft.net") + + HOSTS.iter().any(|&entry| domain.contains(entry)) }) .collect::>(); if !flagged_entries.is_empty() { - // Open guide on how to remove the entries - window.lock().unwrap() - .shell().open("https://liquidbounce.net/docs/Tutorials/Fixing%20hosts%20file%20issues", None)?; - bail!( "The hosts file has been modified to block the Minecraft authentication server.\n\ \n\ @@ -45,7 +55,7 @@ pub async fn check_hosts_file(window: &Arc>) -> Result<()> The file is located at:\n\ {}", flagged_entries.join("\n"), - HOSTS_PATH + hosts_path ); } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 8b0ae8d..4df5d9d 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,6 +1,6 @@ { "productName": "liquidlauncher", - "version": "0.2.2", + "version": "0.2.4", "identifier": "net.ccbluex.liquidlauncher", "build": { "beforeBuildCommand": "npm run build", @@ -13,6 +13,7 @@ "windows": [ { "title": "LiquidLauncher", + "label": "main", "width": 1000, "minWidth": 1000, "height": 670, @@ -28,6 +29,16 @@ ] }, "shadow": true + }, + { + "title": "LiquidBounce Download", + "label": "download_view", + "url": "https://liquidbounce.net/", + "visible": false, + "maximized": true, + "alwaysOnTop": true, + "center": true, + "parent": "main" } ] }, @@ -47,14 +58,16 @@ "shortDescription": "A LiquidBounce launcher for Minecraft", "longDescription": "A LiquidBounce hacked-client launcher for the game Minecraft", "license": "GPL-3.0", - "licenseFile": "LICENSE", + "licenseFile": "../LICENSE", "resources": [], "targets": [ "updater", "msi", "appimage", "deb", - "appimage" + "appimage", + "app", + "nsis" ], "windows": { "certificateThumbprint": null, @@ -83,10 +96,7 @@ "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEU1QkM5MTlDREQ4NkEzNjMKUldSam80YmRuSkc4NVNxS2MzYVZPN1I4a283RkdsS0lPTjVjRWlxQ1JhdzFZUkRtc0c1eEtqSzQK", "endpoints": [ "https://api.liquidbounce.net/api/v1/launcher/releases/{{target}}/{{current_version}}" - ], - "windows": { - "installMode": "basicUi" - } + ] } } } \ No newline at end of file diff --git a/src/lib/Window.svelte b/src/lib/Window.svelte index c3d455a..a10e1d6 100644 --- a/src/lib/Window.svelte +++ b/src/lib/Window.svelte @@ -4,59 +4,79 @@ import MainScreen from "./main/MainScreen.svelte"; import { check } from "@tauri-apps/plugin-updater"; import { relaunch } from "@tauri-apps/plugin-process"; + import { ask } from "@tauri-apps/plugin-dialog"; - check().then((result) => { - console.debug("Update Check Result", result); - if (result && result.available) { - result.downloadAndInstall().then(() => { - relaunch().catch(e => console.error(e)); - }).catch(e => console.error("Download and Install Failed", e)); - } - }).catch(e => console.error("Update Check Failed", e)); + check() + .then(async (result) => { + console.debug("Update Check Result", result); + if (result && result.available) { + if (!await ask("A Launcher update is available. Would you like to install it now?", "LiquidLauncher")) { + return; + } + + result + .downloadAndInstall() + .then(() => { + relaunch().catch(console.error); + }) + .catch((e) => + console.error("Download and Install Failed", e), + ); + } + }) + .catch((e) => console.error("Update Check Failed", e)); // Load options from file let options; - invoke("get_options").then((result) => { - options = result; + invoke("get_options") + .then((result) => { + options = result; - // Debug options - might be interesting to see what's in there - console.debug("Options", options); + // Debug options - might be interesting to see what's in there + console.debug("Options", options); - // Easy way to store options - options.store = function() { - console.debug("Storing options...", options); - invoke("store_options", { options }) - .catch(e => console.error(e)); - }; - }).catch(e => console.error(e)); + // Easy way to store options + options.store = function () { + console.debug("Storing options...", options); + invoke("store_options", { options }).catch((e) => + console.error(e), + ); + }; + }) + .catch((e) => console.error(e)); // Logout from current account function logout() { // Revoke the actual session - invoke("logout", { accountData: options.currentAccount }) - .catch(e => console.error(e)); + invoke("logout", { accountData: options.currentAccount }).catch(console.error); // Remove account data from options data options.currentAccount = null; options.store(); } - invoke("check_online_status").then((result) => { - console.debug("Status", result); - }).catch(e => { - alert("You are offline! Please connect to the internet and restart the app.\n If this problem persists, please contact the developer.\n\n (Error: " + e + ")"); - console.error(e); - }); + // Check if the launcher is online and passes health checks + invoke("check_health") + .then(() => console.info("Health Check passed")) + .catch((e) => { + let message = e; + if (message.startsWith('"')) message = message.slice(1); + if (message.endsWith('"')) message = message.slice(0, -1); + + console.error(message); + alert(message.replace(/\\n/g, "\n")); + + // Open help page + open("https://liquidbounce.net/docs/Tutorials/Fixing%20LiquidLauncher"); + });
-
- -
+
- {#if options } - {#if options.currentAccount } + {#if options} + {#if options.currentAccount} {:else} @@ -64,7 +84,6 @@ {:else}

The launcher is loading...

{/if} -
\ No newline at end of file + diff --git a/src/lib/main/LaunchArea.svelte b/src/lib/main/LaunchArea.svelte index c53552a..157bc2b 100644 --- a/src/lib/main/LaunchArea.svelte +++ b/src/lib/main/LaunchArea.svelte @@ -63,15 +63,14 @@ overflow: hidden; position: relative; display: flex; - align-items: center; + align-items: flex-end; } .version-info .banner .title { font-weight: 800; color: white; font-size: 18px; - max-width: 50%; - margin-left: 20px; + margin: 10px 20px; } .version-info .date { diff --git a/src/lib/main/MainScreen.svelte b/src/lib/main/MainScreen.svelte index 46f5f00..7469e55 100644 --- a/src/lib/main/MainScreen.svelte +++ b/src/lib/main/MainScreen.svelte @@ -291,8 +291,8 @@ }); if (selected) { - for (const path of selected) { - await invoke("install_custom_mod", { branch, mcVersion, path }); + for (const file of selected) { + await invoke("install_custom_mod", { branch, mcVersion, path: file.path }); } requestMods(); diff --git a/src/lib/main/news/News.svelte b/src/lib/main/news/News.svelte index 038d116..8ee73d6 100644 --- a/src/lib/main/news/News.svelte +++ b/src/lib/main/news/News.svelte @@ -15,8 +15,9 @@
-