mirror of
https://github.com/an-anime-team/sleepy-launcher.git
synced 2024-11-25 06:11:36 +03:00
0.5.3
- added "Repair game" button - added `repairer` field to settings file - updated core library From previous commits: - made preparations for environment settings - now launcher hides when you launch the game - now `Config::try_get_wine_executable` can return `Some("wine")` - removed old wine and dxvk versions; added new Wine-GE-Proton and GE-Proton builds
This commit is contained in:
parent
21ee39ad17
commit
4a83100b7e
6 changed files with 214 additions and 7 deletions
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "anime-game-launcher"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
description = "Anime Game launcher"
|
||||
authors = ["Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>"]
|
||||
license = "GPL-3.0"
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e040b40c0598c48630d7a06110a4aaccbcea6c53
|
||||
Subproject commit 5abbea2f1152d25c2855c43d55133a3edc414bc0
|
|
@ -26,6 +26,16 @@ Adw.PreferencesPage page {
|
|||
title: "Game voiceovers";
|
||||
subtitle: "Select voice packages used in game";
|
||||
}
|
||||
|
||||
Gtk.Box {
|
||||
orientation: horizontal;
|
||||
spacing: 8;
|
||||
margin-top: 16;
|
||||
|
||||
Gtk.Button repair_game {
|
||||
label: "Repair game";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Adw.PreferencesGroup {
|
||||
|
|
|
@ -181,14 +181,31 @@ impl Config {
|
|||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Launcher {
|
||||
pub language: String,
|
||||
pub temp: Option<String>
|
||||
pub temp: Option<String>,
|
||||
pub repairer: Repairer
|
||||
}
|
||||
|
||||
impl Default for Launcher {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
language: String::from("en-us"),
|
||||
temp: launcher_dir()
|
||||
temp: launcher_dir(),
|
||||
repairer: Repairer::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Repairer {
|
||||
pub threads: u8,
|
||||
pub fast: bool
|
||||
}
|
||||
|
||||
impl Default for Repairer {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
threads: 4,
|
||||
fast: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
169
src/ui/main.rs
169
src/ui/main.rs
|
@ -131,6 +131,7 @@ pub enum Actions {
|
|||
OpenPreferencesPage,
|
||||
PreferencesGoBack,
|
||||
PerformButtonEvent,
|
||||
RepairGame,
|
||||
ShowProgressBar,
|
||||
UpdateProgress { fraction: Rc<f64>, title: Rc<String> },
|
||||
HideProgressBar,
|
||||
|
@ -224,7 +225,10 @@ impl App {
|
|||
|
||||
receiver.attach(None, move |action| {
|
||||
// Some debug output
|
||||
println!("[main] [update] action: {:?}", action);
|
||||
match &action {
|
||||
Actions::UpdateProgress { .. } => (),
|
||||
action => println!("[main] [update] action: {:?}", action)
|
||||
}
|
||||
|
||||
match action {
|
||||
Actions::OpenPreferencesPage => {
|
||||
|
@ -401,8 +405,6 @@ impl App {
|
|||
|
||||
config::update(config);
|
||||
|
||||
this.widgets.progress_bar.hide();
|
||||
|
||||
this.update_state();
|
||||
}
|
||||
}
|
||||
|
@ -518,6 +520,165 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
Actions::RepairGame => {
|
||||
match config::get() {
|
||||
Ok(config) => {
|
||||
let this = this.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
match repairer::try_get_integrity_files() {
|
||||
Ok(mut files) => {
|
||||
// Add voiceovers files
|
||||
let game = Game::new(&config.game.path);
|
||||
|
||||
if let Ok(voiceovers) = game.get_voice_packages() {
|
||||
for package in voiceovers {
|
||||
if let Ok(mut voiceover_files) = repairer::try_get_voice_integrity_files(package.locale()) {
|
||||
files.append(&mut voiceover_files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.update(Actions::ShowProgressBar).unwrap();
|
||||
|
||||
this.update(Actions::UpdateProgress {
|
||||
fraction: Rc::new(0.0),
|
||||
title: Rc::new(String::from("Verifying files: 0%"))
|
||||
}).unwrap();
|
||||
|
||||
const VERIFIER_THREADS_NUM: u64 = 4;
|
||||
|
||||
let mut total = 0;
|
||||
|
||||
for file in &files {
|
||||
total += file.size;
|
||||
}
|
||||
|
||||
let median_size = total / VERIFIER_THREADS_NUM;
|
||||
let mut i = 0;
|
||||
|
||||
let (sender, receiver) = std::sync::mpsc::channel();
|
||||
|
||||
for _ in 0..VERIFIER_THREADS_NUM {
|
||||
let mut thread_files = Vec::new();
|
||||
let mut thread_files_size = 0;
|
||||
|
||||
while i < files.len() {
|
||||
thread_files.push(files[i].clone());
|
||||
|
||||
thread_files_size += files[i].size;
|
||||
i += 1;
|
||||
|
||||
if thread_files_size >= median_size {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let game_path = config.game.path.clone();
|
||||
let thread_sender = sender.clone();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
for file in thread_files {
|
||||
let status = if config.launcher.repairer.fast {
|
||||
file.fast_verify(&game_path)
|
||||
} else {
|
||||
file.verify(&game_path)
|
||||
};
|
||||
|
||||
thread_sender.send((file, status)).unwrap();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// We have VERIFIER_THREADS_NUM copies of this sender + the original one
|
||||
// receiver will return Err when all the senders will be dropped.
|
||||
// VERIFIER_THREADS_NUM senders will be dropped when threads will finish verifying files
|
||||
// but this one will live as long as current thread exists so we should drop it manually
|
||||
drop(sender);
|
||||
|
||||
let mut broken = Vec::new();
|
||||
let mut processed = 0;
|
||||
|
||||
while let Ok((file, status)) = receiver.recv() {
|
||||
processed += file.size;
|
||||
|
||||
if !status {
|
||||
broken.push(file);
|
||||
}
|
||||
|
||||
let progress = processed as f64 / total as f64;
|
||||
|
||||
this.update(Actions::UpdateProgress {
|
||||
fraction: Rc::new(progress),
|
||||
title: Rc::new(format!("Verifying files: {:.2}%", progress * 100.0))
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
if broken.len() > 0 {
|
||||
this.update(Actions::UpdateProgress {
|
||||
fraction: Rc::new(0.0),
|
||||
title: Rc::new(String::from("Repairing files: 0%"))
|
||||
}).unwrap();
|
||||
|
||||
println!("Found broken files:");
|
||||
|
||||
for file in &broken {
|
||||
println!(" - {}", file.path);
|
||||
}
|
||||
|
||||
let total = broken.len() as f64;
|
||||
|
||||
let is_patch_applied = match Patch::try_fetch(config.patch.servers) {
|
||||
Ok(patch) => patch.is_applied(&config.game.path).unwrap_or(true),
|
||||
Err(_) => true
|
||||
};
|
||||
|
||||
println!("Patch status: {}", is_patch_applied);
|
||||
|
||||
fn should_ignore(path: &str) -> bool {
|
||||
for part in ["UnityPlayer.dll", "xlua.dll", "crashreport.exe", "upload_crash.exe", "vulkan-1.dll"] {
|
||||
if path.contains(part) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
for (i, file) in broken.into_iter().enumerate() {
|
||||
if !is_patch_applied || !should_ignore(&file.path) {
|
||||
if let Err(err) = file.repair(&config.game.path) {
|
||||
this.update(Actions::ToastError(Rc::new((
|
||||
String::from("Failed to repair game file"), err
|
||||
)))).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
let progress = i as f64 / total;
|
||||
|
||||
this.update(Actions::UpdateProgress {
|
||||
fraction: Rc::new(progress),
|
||||
title: Rc::new(format!("Repairing files: {:.2}%", progress * 100.0))
|
||||
}).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
this.update(Actions::HideProgressBar).unwrap();
|
||||
},
|
||||
Err(err) => {
|
||||
this.update(Actions::ToastError(Rc::new((
|
||||
String::from("Failed to get integrity files"), err
|
||||
)))).unwrap();
|
||||
|
||||
this.update(Actions::HideProgressBar).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
Err(err) => this.toast_error("Failed to load config", err)
|
||||
}
|
||||
}
|
||||
|
||||
Actions::ShowProgressBar => {
|
||||
this.widgets.progress_bar.show();
|
||||
}
|
||||
|
@ -567,6 +728,8 @@ impl App {
|
|||
pub fn set_state(&self, state: LauncherState) {
|
||||
println!("[main] [set_state] state: {:?}", &state);
|
||||
|
||||
self.widgets.progress_bar.hide();
|
||||
|
||||
self.widgets.launch_game.set_tooltip_text(None);
|
||||
self.widgets.launch_game.set_sensitive(true);
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ pub struct AppWidgets {
|
|||
pub voiceovers_row: adw::ExpanderRow,
|
||||
pub voieover_components: Rc<Vec<VoiceoverRow>>,
|
||||
|
||||
pub repair_game: gtk::Button,
|
||||
|
||||
pub game_version: gtk::Label,
|
||||
pub patch_version: gtk::Label,
|
||||
|
||||
|
@ -62,6 +64,8 @@ impl AppWidgets {
|
|||
voiceovers_row: get_object(&builder, "voiceovers_row")?,
|
||||
voieover_components: Default::default(),
|
||||
|
||||
repair_game: get_object(&builder, "repair_game")?,
|
||||
|
||||
game_version: get_object(&builder, "game_version")?,
|
||||
patch_version: get_object(&builder, "patch_version")?,
|
||||
|
||||
|
@ -160,6 +164,7 @@ impl AppWidgets {
|
|||
#[derive(Debug, Clone, glib::Downgrade)]
|
||||
pub enum Actions {
|
||||
VoiceoverPerformAction(Rc<usize>),
|
||||
RepairGame,
|
||||
DxvkPerformAction(Rc<usize>),
|
||||
WinePerformAction(Rc<(usize, usize)>),
|
||||
UpdateDxvkComboRow,
|
||||
|
@ -226,6 +231,8 @@ impl App {
|
|||
|
||||
/// Add default events and values to the widgets
|
||||
fn init_events(self) -> Self {
|
||||
self.widgets.repair_game.connect_clicked(Actions::RepairGame.into_fn(&self));
|
||||
|
||||
// Voiceover download/delete button event
|
||||
for (i, row) in (&*self.widgets.voieover_components).into_iter().enumerate() {
|
||||
row.button.connect_clicked(clone!(@weak self as this => move |_| {
|
||||
|
@ -325,6 +332,16 @@ impl App {
|
|||
println!("[general page] [update] action: {:?}", &action);
|
||||
|
||||
match action {
|
||||
Actions::RepairGame => {
|
||||
let option = (&*this.app).take();
|
||||
this.app.set(option.clone());
|
||||
|
||||
let app = option.unwrap();
|
||||
|
||||
app.update(super::main::Actions::PreferencesGoBack).unwrap();
|
||||
app.update(super::main::Actions::RepairGame).unwrap();
|
||||
}
|
||||
|
||||
Actions::VoiceoverPerformAction(i) => {
|
||||
let component = this.widgets.voieover_components[*i].clone();
|
||||
|
||||
|
|
Loading…
Reference in a new issue