From 2ce9e44a869e621befff6a2af9a75d9a93b10b71 Mon Sep 17 00:00:00 2001 From: Observer KRypt0n_ Date: Thu, 28 Jul 2022 18:21:27 +0200 Subject: [PATCH] 0.3.0 - added usage of config's temp path to all the installers - added processing of `WineNotInstalled` and `PrefixNotExists` actions - added (forgotten) launcher states updating --- Cargo.toml | 2 +- src/lib/launcher/states.rs | 3 + src/ui/first_run.rs | 8 + src/ui/main.rs | 219 +++++++++++++++++++++------- src/ui/traits/download_component.rs | 9 +- 5 files changed, 183 insertions(+), 58 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3cbef66..5823269 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "anime-game-launcher" -version = "0.2.1" +version = "0.3.0" description = "Anime Game launcher" authors = ["Nikita Podvirnyy "] license = "GPL-3.0" diff --git a/src/lib/launcher/states.rs b/src/lib/launcher/states.rs index c43c3a9..7f45069 100644 --- a/src/lib/launcher/states.rs +++ b/src/lib/launcher/states.rs @@ -42,16 +42,19 @@ impl LauncherState { pub fn get(status_page: Option<&libadwaita::StatusPage>) -> std::io::Result { let config = config::get()?; + // Check wine existance if config.game.wine.selected == None { return Ok(Self::WineNotInstalled); } + // Check prefix existance let prefix = WinePrefix::new(&config.game.wine.prefix); if !prefix.exists() { return Ok(Self::PrefixNotExists); } + // Check game installation status if let Some(status_page) = &status_page { status_page.set_description(Some("Updating game info...")); } diff --git a/src/ui/first_run.rs b/src/ui/first_run.rs index 7166691..b8bfc66 100644 --- a/src/ui/first_run.rs +++ b/src/ui/first_run.rs @@ -214,6 +214,10 @@ impl App { let mut wine_version_installer = Installer::new(&wine_version_copy.uri).unwrap(); + if let Some(temp_folder) = config.launcher.temp { + wine_version_installer.temp_folder = temp_folder; + } + wine_version_installer.install(&config.game.wine.builds, move |state| { sender.send(state).unwrap(); }); @@ -242,6 +246,10 @@ impl App { // Prepare DXVK downloader let mut dxvk_version_installer = Installer::new(&dxvk_version.uri).unwrap(); + if let Some(temp_folder) = config.launcher.temp { + dxvk_version_installer.temp_folder = temp_folder; + } + let dxvk_version = dxvk_version.clone(); let progress_bar = progress_bar.clone(); diff --git a/src/ui/main.rs b/src/ui/main.rs index 68ef6ad..2c61241 100644 --- a/src/ui/main.rs +++ b/src/ui/main.rs @@ -20,6 +20,11 @@ use crate::lib::config; use crate::lib::game; use crate::lib::tasks; use crate::lib::launcher::states::LauncherState; +use crate::lib::wine::{ + Version as WineVersion, + List as WineList +}; +use crate::lib::wine_prefix::WinePrefix; /// This structure is used to describe widgets used in application /// @@ -124,7 +129,6 @@ pub enum Actions { OpenPreferencesPage, PreferencesGoBack, PerformButtonEvent, - DownloadDiff(Rc), ShowProgressBar, UpdateProgress { fraction: Rc, title: Rc }, HideProgressBar, @@ -214,12 +218,7 @@ impl App { receiver.attach(None, move |action| { // Some debug output - match &action { - // Actions::UpdateProgress { .. } | - // Actions::UpdateProgressByState(_) => (), - - action => println!("[main] [update] action: {:?}", action) - } + println!("[main] [update] action: {:?}", action); match action { Actions::OpenPreferencesPage => { @@ -248,57 +247,159 @@ impl App { this.values.set(values); - match state { - LauncherState::Launch => { - // Display toast message if the game is failed to run - if let Err(err) = game::run(false) { - this.toast_error("Failed to run game", err); + match config::get() { + Ok(mut config) => { + match state { + LauncherState::Launch => { + // Display toast message if the game is failed to run + if let Err(err) = game::run(false) { + this.toast_error("Failed to run game", err); + } + }, + + LauncherState::PatchAvailable(_) => todo!(), + + LauncherState::WineNotInstalled => { + match WineList::list_downloaded(&config.game.wine.builds) { + Ok(list) => { + for version in list { + if version.recommended { + config.game.wine.selected = Some(version.name); + + config::update(config.clone()); + + break; + } + } + + if config.game.wine.selected == None { + match WineVersion::latest() { + Ok(wine) => { + match Installer::new(wine.uri) { + Ok(mut installer) => { + if let Some(temp_folder) = config.launcher.temp { + installer.temp_folder = temp_folder; + } + + let (sender, receiver) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); + let this = this.clone(); + + this.update(Actions::ShowProgressBar).unwrap(); + + // Download wine version + // We need to update components from the main thread + receiver.attach(None, move |state| { + match this.widgets.progress_bar.update_from_state(state) { + ProgressUpdateResult::Updated => (), + + ProgressUpdateResult::Error(msg, err) => { + this.update(Actions::ToastError(Rc::new((msg, err)))).unwrap(); + this.update(Actions::HideProgressBar).unwrap(); + } + + ProgressUpdateResult::Finished => { + let mut config = config::get().unwrap(); + + config.game.wine.selected = Some(wine.name.clone()); + + config::update(config); + + this.update(Actions::HideProgressBar).unwrap(); + this.update_state(); + } + } + + glib::Continue(true) + }); + + // Download wine version in separate thread to not to freeze the main one + std::thread::spawn(move || { + installer.install(config.game.wine.builds, move |state| { + sender.send(state).unwrap(); + }); + }); + }, + Err(err) => this.toast_error("Failed to init wine version installer", err) + } + }, + Err(err) => this.toast_error("Failed to get latest wine version", err) + } + } + + else { + this.update_state(); + } + }, + Err(err) => this.toast_error("Failed to list downloaded wine versions", err) + } + } + + LauncherState::PrefixNotExists => { + let prefix = WinePrefix::new(&config.game.wine.prefix); + + match config.try_get_selected_wine_info() { + Some(wine) => { + let this = this.clone(); + + std::thread::spawn(move || { + this.widgets.launch_game.set_sensitive(false); + + if let Err(err) = prefix.update(&config.game.wine.builds, wine) { + this.toast_error("Failed to create wine prefix", err); + } + + this.widgets.launch_game.set_sensitive(true); + + this.update_state(); + }); + }, + None => this.toast_error("Failed to get selected wine version", Error::last_os_error()) + } + } + + LauncherState::VoiceUpdateAvailable(diff) | + LauncherState::VoiceNotInstalled(diff) | + LauncherState::GameUpdateAvailable(diff) | + LauncherState::GameNotInstalled(diff) => { + let (sender, receiver) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); + let this = this.clone(); + + this.update(Actions::ShowProgressBar).unwrap(); + + // Download diff + // We need to update components from the main thread + receiver.attach(None, move |state| { + match this.widgets.progress_bar.update_from_state(state) { + ProgressUpdateResult::Updated => (), + + ProgressUpdateResult::Error(msg, err) => { + this.update(Actions::ToastError(Rc::new((msg, err)))).unwrap(); + this.update(Actions::HideProgressBar).unwrap(); + } + + ProgressUpdateResult::Finished => { + this.update(Actions::HideProgressBar).unwrap(); + + this.update_state(); + } + } + + glib::Continue(true) + }); + + // Download diff in separate thread to not to freeze the main one + std::thread::spawn(move || { + diff.install_to_by(config.game.path, config.launcher.temp, move |state| { + sender.send(state).unwrap(); + }).unwrap(); + }); + }, + + LauncherState::GameOutdated(_) => (), + LauncherState::VoiceOutdated(_) => () } }, - - LauncherState::PatchAvailable(_) => todo!(), - - LauncherState::WineNotInstalled => todo!(), - LauncherState::PrefixNotExists => todo!(), - - LauncherState::VoiceUpdateAvailable(diff) | - LauncherState::VoiceNotInstalled(diff) | - LauncherState::GameUpdateAvailable(diff) | - LauncherState::GameNotInstalled(diff) => { - this.update(Actions::DownloadDiff(Rc::new(diff))).unwrap(); - }, - - LauncherState::GameOutdated(_) => (), - LauncherState::VoiceOutdated(_) => () - } - } - - Actions::DownloadDiff(diff) => { - match config::get() { - Ok(config) => { - let diff = (*diff).clone(); - let this = this.clone(); - - std::thread::spawn(move || { - let this = this.clone(); - - this.update(Actions::ShowProgressBar).unwrap(); - - // Download diff - diff.install_to_by(config.game.path, config.launcher.temp, move |state| { - match this.widgets.progress_bar.update_from_state(state) { - ProgressUpdateResult::Updated => (), - ProgressUpdateResult::Error(msg, err) => this.update(Actions::ToastError(Rc::new((msg, err)))).unwrap(), - ProgressUpdateResult::Finished => this.update(Actions::HideProgressBar).unwrap() - } - }).unwrap(); - }); - }, - Err(err) => { - this.update(Actions::ToastError(Rc::new(( - String::from("Failed to load config"), err - )))).unwrap(); - } + Err(err) => this.toast_error("Failed to load config", err) } } @@ -351,6 +452,9 @@ impl App { pub fn set_state(&self, state: LauncherState) { println!("[main] [set_state] state: {:?}", &state); + self.widgets.launch_game.set_tooltip_text(None); + self.widgets.launch_game.set_sensitive(true); + match state { LauncherState::Launch => { self.widgets.launch_game.set_label("Launch"); @@ -396,6 +500,9 @@ impl App { pub fn update_state(&self) { let this = self.clone(); + this.widgets.status_page.show(); + this.widgets.launcher_content.hide(); + std::thread::spawn(move || { match LauncherState::get(Some(&this.widgets.status_page)) { Ok(state) => { diff --git a/src/ui/traits/download_component.rs b/src/ui/traits/download_component.rs index dce97d3..27bffbf 100644 --- a/src/ui/traits/download_component.rs +++ b/src/ui/traits/download_component.rs @@ -7,6 +7,8 @@ use std::path::Path; use anime_game_core::prelude::*; use wait_not_await::Await; +use crate::lib::config; + #[derive(Debug)] pub enum DownloadingResult { DownloadingError(std::io::Error), @@ -73,7 +75,12 @@ pub trait DownloadComponent { let (send, recv) = std::sync::mpsc::channel(); - let installer = Installer::new(self.get_download_uri())?; + let mut installer = Installer::new(self.get_download_uri())?; + + if let Some(temp_folder) = config::get()?.launcher.temp { + installer.temp_folder = temp_folder; + } + let installation_path = installation_path.to_string(); send.send(installer).unwrap();