- added usage of config's temp path to all the installers
- added processing of `WineNotInstalled` and `PrefixNotExists` actions
- added (forgotten) launcher states updating
This commit is contained in:
Observer KRypt0n_ 2022-07-28 18:21:27 +02:00
parent 69e1c719e5
commit 2ce9e44a86
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
5 changed files with 183 additions and 58 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "anime-game-launcher" name = "anime-game-launcher"
version = "0.2.1" version = "0.3.0"
description = "Anime Game launcher" description = "Anime Game launcher"
authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"] authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"]
license = "GPL-3.0" license = "GPL-3.0"

View file

@ -42,16 +42,19 @@ impl LauncherState {
pub fn get(status_page: Option<&libadwaita::StatusPage>) -> std::io::Result<Self> { pub fn get(status_page: Option<&libadwaita::StatusPage>) -> std::io::Result<Self> {
let config = config::get()?; let config = config::get()?;
// Check wine existance
if config.game.wine.selected == None { if config.game.wine.selected == None {
return Ok(Self::WineNotInstalled); return Ok(Self::WineNotInstalled);
} }
// Check prefix existance
let prefix = WinePrefix::new(&config.game.wine.prefix); let prefix = WinePrefix::new(&config.game.wine.prefix);
if !prefix.exists() { if !prefix.exists() {
return Ok(Self::PrefixNotExists); return Ok(Self::PrefixNotExists);
} }
// Check game installation status
if let Some(status_page) = &status_page { if let Some(status_page) = &status_page {
status_page.set_description(Some("Updating game info...")); status_page.set_description(Some("Updating game info..."));
} }

View file

@ -214,6 +214,10 @@ impl App {
let mut wine_version_installer = Installer::new(&wine_version_copy.uri).unwrap(); 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| { wine_version_installer.install(&config.game.wine.builds, move |state| {
sender.send(state).unwrap(); sender.send(state).unwrap();
}); });
@ -242,6 +246,10 @@ impl App {
// Prepare DXVK downloader // Prepare DXVK downloader
let mut dxvk_version_installer = Installer::new(&dxvk_version.uri).unwrap(); 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 dxvk_version = dxvk_version.clone();
let progress_bar = progress_bar.clone(); let progress_bar = progress_bar.clone();

View file

@ -20,6 +20,11 @@ use crate::lib::config;
use crate::lib::game; use crate::lib::game;
use crate::lib::tasks; use crate::lib::tasks;
use crate::lib::launcher::states::LauncherState; 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 /// This structure is used to describe widgets used in application
/// ///
@ -124,7 +129,6 @@ pub enum Actions {
OpenPreferencesPage, OpenPreferencesPage,
PreferencesGoBack, PreferencesGoBack,
PerformButtonEvent, PerformButtonEvent,
DownloadDiff(Rc<VersionDiff>),
ShowProgressBar, ShowProgressBar,
UpdateProgress { fraction: Rc<f64>, title: Rc<String> }, UpdateProgress { fraction: Rc<f64>, title: Rc<String> },
HideProgressBar, HideProgressBar,
@ -214,12 +218,7 @@ impl App {
receiver.attach(None, move |action| { receiver.attach(None, move |action| {
// Some debug output // Some debug output
match &action { println!("[main] [update] action: {:?}", action);
// Actions::UpdateProgress { .. } |
// Actions::UpdateProgressByState(_) => (),
action => println!("[main] [update] action: {:?}", action)
}
match action { match action {
Actions::OpenPreferencesPage => { Actions::OpenPreferencesPage => {
@ -248,57 +247,159 @@ impl App {
this.values.set(values); this.values.set(values);
match state { match config::get() {
LauncherState::Launch => { Ok(mut config) => {
// Display toast message if the game is failed to run match state {
if let Err(err) = game::run(false) { LauncherState::Launch => {
this.toast_error("Failed to run game", err); // 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::<InstallerUpdate>(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::<InstallerUpdate>(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(_) => ()
} }
}, },
Err(err) => this.toast_error("Failed to load config", err)
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();
}
} }
} }
@ -351,6 +452,9 @@ impl App {
pub fn set_state(&self, state: LauncherState) { pub fn set_state(&self, state: LauncherState) {
println!("[main] [set_state] state: {:?}", &state); println!("[main] [set_state] state: {:?}", &state);
self.widgets.launch_game.set_tooltip_text(None);
self.widgets.launch_game.set_sensitive(true);
match state { match state {
LauncherState::Launch => { LauncherState::Launch => {
self.widgets.launch_game.set_label("Launch"); self.widgets.launch_game.set_label("Launch");
@ -396,6 +500,9 @@ impl App {
pub fn update_state(&self) { pub fn update_state(&self) {
let this = self.clone(); let this = self.clone();
this.widgets.status_page.show();
this.widgets.launcher_content.hide();
std::thread::spawn(move || { std::thread::spawn(move || {
match LauncherState::get(Some(&this.widgets.status_page)) { match LauncherState::get(Some(&this.widgets.status_page)) {
Ok(state) => { Ok(state) => {

View file

@ -7,6 +7,8 @@ use std::path::Path;
use anime_game_core::prelude::*; use anime_game_core::prelude::*;
use wait_not_await::Await; use wait_not_await::Await;
use crate::lib::config;
#[derive(Debug)] #[derive(Debug)]
pub enum DownloadingResult { pub enum DownloadingResult {
DownloadingError(std::io::Error), DownloadingError(std::io::Error),
@ -73,7 +75,12 @@ pub trait DownloadComponent {
let (send, recv) = std::sync::mpsc::channel(); 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(); let installation_path = installation_path.to_string();
send.send(installer).unwrap(); send.send(installer).unwrap();