mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-01-30 04:23:31 +03:00
feat: removed patch integration
This commit is contained in:
parent
db3dc481f6
commit
252c948073
14 changed files with 36 additions and 575 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -39,8 +39,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anime-game-core"
|
||||
version = "1.13.5"
|
||||
source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.13.5#11e48e47563acf97a6885d3cc369875031dc5f61"
|
||||
version = "1.15.0"
|
||||
source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.15.0#e34a35e04dd97d8268e47769f82591100b3354ae"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bzip2",
|
||||
|
@ -88,8 +88,8 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anime-launcher-sdk"
|
||||
version = "1.8.13"
|
||||
source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.8.13#1669dceafce3eaa3e9332fb4ac6ff78ea9fb1639"
|
||||
version = "1.10.0"
|
||||
source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.10.0#916d4b56e0de0b3ed7720603da2090cbd9a11210"
|
||||
dependencies = [
|
||||
"anime-game-core",
|
||||
"anyhow",
|
||||
|
@ -1288,9 +1288,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "glib-build-tools"
|
||||
version = "0.17.10"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a65d79efe318ef2cbbbb37032b125866fd82c34ea44c816132621bbc552e716"
|
||||
checksum = "3431c56f463443cba9bc3600248bc6d680cb614c2ee1cdd39dab5415bd12ac5c"
|
||||
|
||||
[[package]]
|
||||
name = "glib-macros"
|
||||
|
@ -1971,9 +1971,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
|||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "4.2.0"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a083c0c7e5e4a8ec4176346cf61f67ac674e8bfb059d9226e1c54a96b377c12"
|
||||
checksum = "cfabf1927dce4d6fdf563d63328a0a506101ced3ec780ca2135747336c98cef8"
|
||||
dependencies = [
|
||||
"is-wsl",
|
||||
"libc",
|
||||
|
|
|
@ -15,12 +15,12 @@ lto = true
|
|||
opt-level = "s"
|
||||
|
||||
[build-dependencies]
|
||||
glib-build-tools = "0.17"
|
||||
glib-build-tools = "0.18"
|
||||
|
||||
[dependencies.anime-launcher-sdk]
|
||||
git = "https://github.com/an-anime-team/anime-launcher-sdk"
|
||||
tag = "1.8.13"
|
||||
features = ["all", "genshin", "genshin-patch"]
|
||||
tag = "1.10.0"
|
||||
features = ["all", "genshin"]
|
||||
|
||||
# path = "../anime-launcher-sdk" # ! for dev purposes only
|
||||
|
||||
|
@ -30,7 +30,7 @@ gtk = { package = "gtk4", version = "0.6", features = ["v4_8"] }
|
|||
adw = { package = "libadwaita", version = "0.4", features = ["v1_2"] }
|
||||
|
||||
rfd = { version = "0.11", features = ["xdg-portal"], default-features = false }
|
||||
open = "4.0"
|
||||
open = "5.0.0"
|
||||
whatadistro = "0.1.0"
|
||||
|
||||
serde_json = "1.0"
|
||||
|
|
|
@ -209,13 +209,10 @@ fn main() {
|
|||
return;
|
||||
}
|
||||
|
||||
LauncherState::PredownloadAvailable { .. } |
|
||||
LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status: PatchStatus::NotAvailable, .. }, .. } => {
|
||||
if just_run_game {
|
||||
anime_launcher_sdk::genshin::game::run().expect("Failed to run the game");
|
||||
LauncherState::PredownloadAvailable { .. } if just_run_game => {
|
||||
anime_launcher_sdk::genshin::game::run().expect("Failed to run the game");
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_ => ()
|
||||
|
|
|
@ -25,7 +25,6 @@ pub struct DefaultPathsApp {
|
|||
game_china: PathBuf,
|
||||
fps_unlocker: PathBuf,
|
||||
components: PathBuf,
|
||||
patch: PathBuf,
|
||||
temp: PathBuf
|
||||
}
|
||||
|
||||
|
@ -39,7 +38,6 @@ pub enum Folders {
|
|||
GameChina,
|
||||
FpsUnlocker,
|
||||
Components,
|
||||
Patch,
|
||||
Temp
|
||||
}
|
||||
|
||||
|
@ -194,17 +192,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
|
|||
connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::Components)
|
||||
},
|
||||
|
||||
adw::ActionRow {
|
||||
set_title: &tr!("patch-folder"),
|
||||
set_icon_name: Some("folder-symbolic"),
|
||||
set_activatable: true,
|
||||
|
||||
#[watch]
|
||||
set_subtitle: model.patch.to_str().unwrap(),
|
||||
|
||||
connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::Patch)
|
||||
},
|
||||
|
||||
adw::ActionRow {
|
||||
set_title: &tr!("temp-folder"),
|
||||
set_icon_name: Some("folder-symbolic"),
|
||||
|
@ -302,7 +289,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
|
|||
game_china: CONFIG.game.path.china.clone(),
|
||||
fps_unlocker: CONFIG.game.enhancements.fps_unlocker.path.clone(),
|
||||
components: CONFIG.components.path.clone(),
|
||||
patch: CONFIG.patch.path.clone(),
|
||||
|
||||
#[allow(clippy::or_fun_call)]
|
||||
temp: CONFIG.launcher.temp.clone().unwrap_or(std::env::temp_dir())
|
||||
|
@ -337,7 +323,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
|
|||
self.game_china = result.join(concat!("Yu", "anS", "hen"));
|
||||
self.fps_unlocker = result.join("fps-unlocker");
|
||||
self.components = result.join("components");
|
||||
self.patch = result.join("patch");
|
||||
self.temp = result.clone();
|
||||
|
||||
self.launcher = result;
|
||||
|
@ -350,7 +335,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
|
|||
Folders::GameChina => self.game_china = result,
|
||||
Folders::FpsUnlocker => self.fps_unlocker = result,
|
||||
Folders::Components => self.components = result,
|
||||
Folders::Patch => self.patch = result,
|
||||
Folders::Temp => self.temp = result
|
||||
}
|
||||
}
|
||||
|
@ -374,7 +358,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
|
|||
(old_config.game.path.global, &self.game_global),
|
||||
(old_config.game.path.china, &self.game_china),
|
||||
(old_config.components.path, &self.components),
|
||||
(old_config.patch.path, &self.patch),
|
||||
|
||||
(old_config.game.enhancements.fps_unlocker.path, &self.fps_unlocker)
|
||||
];
|
||||
|
@ -437,7 +420,6 @@ impl DefaultPathsApp {
|
|||
config.game.path.global = self.game_global.clone();
|
||||
config.game.path.china = self.game_china.clone();
|
||||
config.components.path = self.components.clone();
|
||||
config.patch.path = self.patch.clone();
|
||||
config.launcher.temp = Some(self.temp.clone());
|
||||
|
||||
config.game.enhancements.fps_unlocker.path = self.fps_unlocker.clone();
|
||||
|
|
|
@ -9,7 +9,6 @@ use anime_launcher_sdk::components::loader::ComponentsLoader;
|
|||
use crate::*;
|
||||
|
||||
use super::welcome::*;
|
||||
use super::tos_warning::*;
|
||||
use super::dependencies::*;
|
||||
use super::default_paths::*;
|
||||
use super::select_voiceovers::*;
|
||||
|
@ -22,7 +21,6 @@ pub static mut MAIN_WINDOW: Option<adw::ApplicationWindow> = None;
|
|||
|
||||
pub struct FirstRunApp {
|
||||
welcome: AsyncController<WelcomeApp>,
|
||||
tos_warning: AsyncController<TosWarningApp>,
|
||||
dependencies: AsyncController<DependenciesApp>,
|
||||
default_paths: AsyncController<DefaultPathsApp>,
|
||||
select_voiceovers: AsyncController<SelectVoiceoversApp>,
|
||||
|
@ -40,7 +38,6 @@ pub struct FirstRunApp {
|
|||
pub enum FirstRunAppMsg {
|
||||
SetLoadingStatus(Option<Option<String>>),
|
||||
|
||||
ScrollToTosWarning,
|
||||
ScrollToDependencies,
|
||||
ScrollToDefaultPaths,
|
||||
ScrollToSelectVoiceovers,
|
||||
|
@ -100,7 +97,6 @@ impl SimpleComponent for FirstRunApp {
|
|||
set_allow_scroll_wheel: false,
|
||||
|
||||
append = model.welcome.widget(),
|
||||
append = model.tos_warning.widget(),
|
||||
append = model.dependencies.widget(),
|
||||
append = model.default_paths.widget(),
|
||||
append = model.select_voiceovers.widget(),
|
||||
|
@ -135,10 +131,6 @@ impl SimpleComponent for FirstRunApp {
|
|||
.launch(())
|
||||
.forward(sender.input_sender(), std::convert::identity),
|
||||
|
||||
tos_warning: TosWarningApp::builder()
|
||||
.launch(())
|
||||
.forward(sender.input_sender(), std::convert::identity),
|
||||
|
||||
dependencies: DependenciesApp::builder()
|
||||
.launch(())
|
||||
.forward(sender.input_sender(), std::convert::identity),
|
||||
|
@ -190,12 +182,6 @@ impl SimpleComponent for FirstRunApp {
|
|||
self.loading = status;
|
||||
}
|
||||
|
||||
FirstRunAppMsg::ScrollToTosWarning => {
|
||||
self.title = tr!("tos-violation-warning");
|
||||
|
||||
self.carousel.scroll_to(self.tos_warning.widget(), true);
|
||||
}
|
||||
|
||||
FirstRunAppMsg::ScrollToDependencies => {
|
||||
self.title = tr!("dependencies");
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
pub mod main;
|
||||
pub mod welcome;
|
||||
pub mod tos_warning;
|
||||
pub mod dependencies;
|
||||
pub mod default_paths;
|
||||
pub mod select_voiceovers;
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
use relm4::prelude::*;
|
||||
use relm4::component::*;
|
||||
|
||||
use adw::prelude::*;
|
||||
|
||||
use anime_launcher_sdk::is_available;
|
||||
|
||||
use crate::*;
|
||||
|
||||
use super::main::FirstRunAppMsg;
|
||||
|
||||
use super::main::MAIN_WINDOW;
|
||||
|
||||
pub struct TosWarningApp;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TosWarningAppMsg {
|
||||
Continue,
|
||||
Exit
|
||||
}
|
||||
|
||||
#[relm4::component(async, pub)]
|
||||
impl SimpleAsyncComponent for TosWarningApp {
|
||||
type Init = ();
|
||||
type Input = TosWarningAppMsg;
|
||||
type Output = FirstRunAppMsg;
|
||||
|
||||
view! {
|
||||
adw::PreferencesPage {
|
||||
set_hexpand: true,
|
||||
|
||||
add = &adw::PreferencesGroup {
|
||||
set_valign: gtk::Align::Center,
|
||||
set_vexpand: true,
|
||||
|
||||
gtk::Label {
|
||||
set_label: &tr!("tos-violation-warning"),
|
||||
add_css_class: "title-1"
|
||||
}
|
||||
},
|
||||
|
||||
add = &adw::PreferencesGroup {
|
||||
gtk::Label {
|
||||
set_label: &tr!("tos-violation-warning-message"),
|
||||
set_wrap: true,
|
||||
set_selectable: true
|
||||
}
|
||||
},
|
||||
|
||||
add = &adw::PreferencesGroup {
|
||||
set_valign: gtk::Align::Center,
|
||||
set_vexpand: true,
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_halign: gtk::Align::Center,
|
||||
set_spacing: 8,
|
||||
|
||||
gtk::Button {
|
||||
set_label: &tr!("continue"),
|
||||
set_css_classes: &["suggested-action", "pill"],
|
||||
|
||||
connect_clicked => TosWarningAppMsg::Continue
|
||||
},
|
||||
|
||||
gtk::Button {
|
||||
set_label: &tr!("exit"),
|
||||
add_css_class: "pill",
|
||||
|
||||
connect_clicked => TosWarningAppMsg::Exit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn init(
|
||||
_init: Self::Init,
|
||||
root: Self::Root,
|
||||
_sender: AsyncComponentSender<Self>,
|
||||
) -> AsyncComponentParts<Self> {
|
||||
let model = Self;
|
||||
let widgets = view_output!();
|
||||
|
||||
AsyncComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
async fn update(&mut self, msg: Self::Input, sender: AsyncComponentSender<Self>) {
|
||||
match msg {
|
||||
#[allow(unused_must_use)]
|
||||
TosWarningAppMsg::Continue => {
|
||||
let dialog = adw::MessageDialog::new(
|
||||
unsafe { MAIN_WINDOW.as_ref() },
|
||||
Some(&tr!("tos-dialog-title")),
|
||||
Some(&tr!("tos-dialog-message"))
|
||||
);
|
||||
|
||||
dialog.add_responses(&[
|
||||
("exit", &tr!("exit")),
|
||||
("continue", &tr!("agree"))
|
||||
]);
|
||||
|
||||
dialog.connect_response(None, move |_, response| {
|
||||
match response {
|
||||
"exit" => relm4::main_application().quit(),
|
||||
|
||||
"continue" => {
|
||||
if is_available("git") && is_available("xdelta3") {
|
||||
sender.output(Self::Output::ScrollToDefaultPaths);
|
||||
} else {
|
||||
sender.output(Self::Output::ScrollToDependencies);
|
||||
}
|
||||
}
|
||||
|
||||
_ => unreachable!()
|
||||
}
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
TosWarningAppMsg::Exit => relm4::main_application().quit()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ use relm4::component::*;
|
|||
|
||||
use adw::prelude::*;
|
||||
|
||||
use anime_launcher_sdk::is_available;
|
||||
|
||||
use crate::*;
|
||||
|
||||
use super::main::FirstRunAppMsg;
|
||||
|
@ -83,7 +85,11 @@ impl SimpleAsyncComponent for WelcomeApp {
|
|||
match msg {
|
||||
#[allow(unused_must_use)]
|
||||
WelcomeAppMsg::Continue => {
|
||||
sender.output(Self::Output::ScrollToTosWarning);
|
||||
if is_available("git") && is_available("xdelta3") {
|
||||
sender.output(Self::Output::ScrollToDefaultPaths);
|
||||
} else {
|
||||
sender.output(Self::Output::ScrollToDependencies);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
use relm4::prelude::*;
|
||||
|
||||
use crate::*;
|
||||
|
||||
use super::{App, AppMsg};
|
||||
|
||||
pub fn apply_patch(sender: ComponentSender<App>, patch: PlayerPatch, rename_mhypbase: bool) {
|
||||
match patch.status() {
|
||||
PatchStatus::NotAvailable |
|
||||
PatchStatus::Outdated { .. } |
|
||||
PatchStatus::Preparation { .. } => unreachable!(),
|
||||
|
||||
PatchStatus::Testing { .. } |
|
||||
PatchStatus::Available { .. } => {
|
||||
sender.input(AppMsg::DisableButtons(true));
|
||||
|
||||
let config = Config::get().unwrap();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
if let Err(err) = patch.apply(config.game.path.for_edition(config.launcher.edition), config.patch.root) {
|
||||
tracing::error!("Failed to patch the game");
|
||||
|
||||
sender.input(AppMsg::Toast {
|
||||
title: tr!("game-patching-error"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
}
|
||||
|
||||
else if rename_mhypbase {
|
||||
let game_folder = config.game.path.for_edition(patch.edition);
|
||||
|
||||
let mhypbase = game_folder.join("mhypbase.dll");
|
||||
let mhypbase_bak = game_folder.join("mhypbase.dll.bak");
|
||||
|
||||
if mhypbase.exists() {
|
||||
if let Err(err) = std::fs::rename(mhypbase, mhypbase_bak) {
|
||||
tracing::error!("Failed to rename mhypbase file");
|
||||
|
||||
sender.input(AppMsg::Toast {
|
||||
title: tr!("game-patching-error"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sender.input(AppMsg::DisableButtons(false));
|
||||
sender.input(AppMsg::UpdateLauncherState {
|
||||
perform_on_download_needed: false,
|
||||
show_status_page: true
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use std::process::Command;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use relm4::prelude::*;
|
||||
|
||||
|
@ -19,7 +20,12 @@ pub fn disable_telemetry(sender: ComponentSender<App>) {
|
|||
.collect::<Vec<String>>()
|
||||
.join(" ; ");
|
||||
|
||||
let output = if config.patch.root {
|
||||
// TODO: perhaps find some another way? Or doesn't matter?
|
||||
let use_root = std::env::var("LAUNCHER_USE_ROOT")
|
||||
.map(|var| var == "1")
|
||||
.unwrap_or_else(|_| !PathBuf::from("/.flatpak-info").exists());
|
||||
|
||||
let output = if use_root {
|
||||
Command::new("pkexec")
|
||||
.arg("bash")
|
||||
.arg("-c")
|
||||
|
|
|
@ -11,7 +11,6 @@ use adw::prelude::*;
|
|||
use gtk::glib::clone;
|
||||
|
||||
mod repair_game;
|
||||
mod apply_patch;
|
||||
mod download_wine;
|
||||
mod create_prefix;
|
||||
mod download_diff;
|
||||
|
@ -79,10 +78,6 @@ pub enum AppMsg {
|
|||
/// was retrieved from the API
|
||||
SetGameDiff(Option<VersionDiff>),
|
||||
|
||||
/// Supposed to be called automatically on app's run when the latest UnityPlayer patch version
|
||||
/// was retrieved from remote repos
|
||||
SetPlayerPatch(Option<PlayerPatch>),
|
||||
|
||||
/// Supposed to be called automatically on app's run when the launcher state was chosen
|
||||
SetLauncherState(Option<LauncherState>),
|
||||
|
||||
|
@ -418,15 +413,6 @@ impl SimpleComponent for App {
|
|||
Some(LauncherState::VoiceUpdateAvailable(_)) |
|
||||
Some(LauncherState::VoiceNotInstalled(_)) => "document-save-symbolic",
|
||||
|
||||
Some(LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status, .. }, .. }) => match status {
|
||||
PatchStatus::NotAvailable |
|
||||
PatchStatus::Outdated { .. } |
|
||||
PatchStatus::Preparation { .. } => "window-close-symbolic",
|
||||
|
||||
PatchStatus::Testing { .. } |
|
||||
PatchStatus::Available { .. } => "document-save-symbolic"
|
||||
}
|
||||
|
||||
Some(LauncherState::TelemetryNotDisabled) => "security-high-symbolic",
|
||||
|
||||
Some(LauncherState::VoiceOutdated(_)) |
|
||||
|
@ -440,8 +426,6 @@ impl SimpleComponent for App {
|
|||
Some(LauncherState::PredownloadAvailable { .. }) => tr!("launch"),
|
||||
|
||||
Some(LauncherState::FolderMigrationRequired { .. }) => tr!("migrate-folders"),
|
||||
Some(LauncherState::PlayerPatchAvailable { .. }) => tr!("apply-patch"),
|
||||
|
||||
Some(LauncherState::TelemetryNotDisabled) => tr!("disable-telemetry"),
|
||||
|
||||
Some(LauncherState::WineNotInstalled) => tr!("download-wine"),
|
||||
|
@ -480,17 +464,7 @@ impl SimpleComponent for App {
|
|||
Some(LauncherState::GameOutdated { .. }) |
|
||||
Some(LauncherState::VoiceOutdated(_)) => false,
|
||||
|
||||
Some(LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status, .. }, .. }) => match status {
|
||||
PatchStatus::NotAvailable |
|
||||
PatchStatus::Outdated { .. } |
|
||||
PatchStatus::Preparation { .. } => false,
|
||||
|
||||
PatchStatus::Testing { .. } |
|
||||
PatchStatus::Available { .. } => true
|
||||
},
|
||||
|
||||
Some(_) => true,
|
||||
|
||||
None => false
|
||||
},
|
||||
|
||||
|
@ -499,17 +473,7 @@ impl SimpleComponent for App {
|
|||
Some(LauncherState::GameOutdated { .. }) |
|
||||
Some(LauncherState::VoiceOutdated(_)) => &["warning", "pill"],
|
||||
|
||||
Some(LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status, .. }, .. }) => match status {
|
||||
PatchStatus::NotAvailable |
|
||||
PatchStatus::Outdated { .. } |
|
||||
PatchStatus::Preparation { .. } => &["error", "pill"],
|
||||
|
||||
PatchStatus::Testing { .. } => &["warning", "pill"],
|
||||
PatchStatus::Available { .. } => &["suggested-action", "pill"]
|
||||
},
|
||||
|
||||
Some(_) => &["suggested-action", "pill"],
|
||||
|
||||
None => &["pill"]
|
||||
},
|
||||
|
||||
|
@ -520,15 +484,6 @@ impl SimpleComponent for App {
|
|||
|
||||
Some(LauncherState::FolderMigrationRequired { .. }) => tr!("migrate-folders-tooltip"),
|
||||
|
||||
Some(LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status, .. }, .. }) => match status {
|
||||
PatchStatus::NotAvailable => tr!("main-window--patch-unavailable-tooltip"),
|
||||
|
||||
PatchStatus::Outdated { .. } |
|
||||
PatchStatus::Preparation { .. } => tr!("main-window--patch-outdated-tooltip"),
|
||||
|
||||
_ => String::new()
|
||||
},
|
||||
|
||||
_ => String::new()
|
||||
}),
|
||||
|
||||
|
@ -926,61 +881,6 @@ impl SimpleComponent for App {
|
|||
}
|
||||
})));
|
||||
|
||||
// Update initial patch status
|
||||
|
||||
tasks.push(std::thread::spawn(clone!(@strong sender => move || {
|
||||
// Sync local patch repo
|
||||
let patch = Patch::new(&CONFIG.patch.path, CONFIG.launcher.edition);
|
||||
|
||||
match patch.is_sync(&CONFIG.patch.servers) {
|
||||
Ok(Some(_)) => (),
|
||||
|
||||
Ok(None) => {
|
||||
for server in &CONFIG.patch.servers {
|
||||
match patch.sync(server) {
|
||||
Ok(_) => break,
|
||||
|
||||
Err(err) => {
|
||||
tracing::error!("Failed to sync patch folder with remote: {server}: {err}");
|
||||
|
||||
sender.input(AppMsg::Toast {
|
||||
title: tr!("patch-sync-failed"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
tracing::error!("Failed to compare local patch folder with remote: {err}");
|
||||
|
||||
sender.input(AppMsg::Toast {
|
||||
title: tr!("patch-state-check-failed"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Get main UnityPlayer patch status
|
||||
sender.input(AppMsg::SetPlayerPatch(match patch.player_patch() {
|
||||
Ok(patch) => Some(patch),
|
||||
|
||||
Err(err) => {
|
||||
tracing::error!("Failed to fetch player patch info: {err}");
|
||||
|
||||
sender.input(AppMsg::Toast {
|
||||
title: tr!("patch-info-fetching-error"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
|
||||
None
|
||||
}
|
||||
}));
|
||||
|
||||
tracing::info!("Updated patch status");
|
||||
})));
|
||||
|
||||
// Update initial game version status
|
||||
|
||||
tasks.push(std::thread::spawn(clone!(@strong sender => move || {
|
||||
|
@ -1045,10 +945,6 @@ impl SimpleComponent for App {
|
|||
"locale" = locale.to_name()
|
||||
})))));
|
||||
}
|
||||
|
||||
StateUpdating::Patch => {
|
||||
sender.input(AppMsg::SetLoadingStatus(Some(Some(tr!("loading-launcher-state--patch")))));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1091,11 +987,6 @@ impl SimpleComponent for App {
|
|||
PREFERENCES_WINDOW.as_ref().unwrap_unchecked().sender().send(PreferencesAppMsg::SetGameDiff(diff));
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
AppMsg::SetPlayerPatch(patch) => unsafe {
|
||||
PREFERENCES_WINDOW.as_ref().unwrap_unchecked().sender().send(PreferencesAppMsg::SetPlayerPatch(patch));
|
||||
}
|
||||
|
||||
AppMsg::SetLauncherState(state) => {
|
||||
self.state = state;
|
||||
}
|
||||
|
@ -1174,16 +1065,12 @@ impl SimpleComponent for App {
|
|||
|
||||
AppMsg::PerformAction => unsafe {
|
||||
match self.state.as_ref().unwrap_unchecked() {
|
||||
LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status: PatchStatus::NotAvailable, .. }, .. } |
|
||||
LauncherState::PredownloadAvailable { .. } |
|
||||
LauncherState::Launch => launch::launch(sender),
|
||||
|
||||
LauncherState::FolderMigrationRequired { from, to, cleanup_folder } =>
|
||||
migrate_folder::migrate_folder(sender, from.to_owned(), to.to_owned(), cleanup_folder.to_owned()),
|
||||
|
||||
LauncherState::PlayerPatchAvailable { patch, disable_mhypbase } =>
|
||||
apply_patch::apply_patch(sender, patch.to_owned(), *disable_mhypbase),
|
||||
|
||||
LauncherState::TelemetryNotDisabled => disable_telemetry::disable_telemetry(sender),
|
||||
|
||||
LauncherState::WineNotInstalled => download_wine::download_wine(sender, self.progress_bar.sender().to_owned()),
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use std::path::Path;
|
||||
|
||||
use relm4::{
|
||||
prelude::*,
|
||||
Sender
|
||||
|
@ -105,59 +103,16 @@ pub fn repair_game(sender: ComponentSender<App>, progress_bar_input: Sender<Prog
|
|||
|
||||
tracing::warn!("Found broken files:\n{}", broken.iter().fold(String::new(), |acc, file| acc + &format!("- {}\n", file.path.to_string_lossy())));
|
||||
|
||||
// Get main patch status
|
||||
|
||||
let player_patch = PlayerPatch::from_folder(&config.patch.path, config.launcher.edition)
|
||||
.and_then(|patch| patch.is_applied(&game_path))
|
||||
.unwrap_or_else(|err| {
|
||||
tracing::warn!("Failed to get player patch status: {err}. Used config value instead: {}", config.patch.apply);
|
||||
|
||||
config.patch.apply
|
||||
});
|
||||
|
||||
tracing::debug!("Patch status: {player_patch}. Disable mhypbase: {}", config.patch.disable_mhypbase);
|
||||
|
||||
fn should_ignore(path: &Path, player_patch: bool, disable_mhypbase: bool) -> bool {
|
||||
// Files managed by launch.bat file
|
||||
for part in ["crashreport.exe", "upload_crash.exe"] {
|
||||
if path.ends_with(part) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// UnityPlayer patch related files
|
||||
if player_patch {
|
||||
for part in ["UnityPlayer.dll", "vulkan-1.dll"] {
|
||||
if path.ends_with(part) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If mhypbase should be disabled
|
||||
if disable_mhypbase && path.ends_with("mhypbase.dll") {
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
for (i, file) in broken.into_iter().enumerate() {
|
||||
if !should_ignore(&file.path, player_patch, config.patch.disable_mhypbase) {
|
||||
tracing::debug!("Repairing file: {}", file.path.to_string_lossy());
|
||||
tracing::debug!("Repairing file: {}", file.path.to_string_lossy());
|
||||
|
||||
if let Err(err) = file.repair(&game_path) {
|
||||
sender.input(AppMsg::Toast {
|
||||
title: tr!("game-file-repairing-error"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
if let Err(err) = file.repair(&game_path) {
|
||||
sender.input(AppMsg::Toast {
|
||||
title: tr!("game-file-repairing-error"),
|
||||
description: Some(err.to_string())
|
||||
});
|
||||
|
||||
tracing::error!("Failed to repair game file: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
tracing::debug!("Skipped file: {}", file.path.to_string_lossy());
|
||||
tracing::error!("Failed to repair game file: {err}");
|
||||
}
|
||||
|
||||
progress_bar_input.send(ProgressBarMsg::UpdateProgress(i as u64 + 1, total));
|
||||
|
|
|
@ -111,10 +111,7 @@ pub struct GeneralApp {
|
|||
components_page: AsyncController<ComponentsPage>,
|
||||
|
||||
game_diff: Option<VersionDiff>,
|
||||
player_patch: Option<PlayerPatch>,
|
||||
|
||||
style: LauncherStyle,
|
||||
|
||||
languages: Vec<String>
|
||||
}
|
||||
|
||||
|
@ -124,10 +121,6 @@ pub enum GeneralAppMsg {
|
|||
/// was retrieved from the API
|
||||
SetGameDiff(Option<VersionDiff>),
|
||||
|
||||
/// Supposed to be called automatically on app's run when the latest UnityPlayer patch version
|
||||
/// was retrieved from remote repos
|
||||
SetPlayerPatch(Option<PlayerPatch>),
|
||||
|
||||
// If one ever wish to change it to accept VoiceLocale
|
||||
// I'd recommend to use clone!(@strong self.locale as locale => move |_| { .. })
|
||||
// in the VoicePackage component
|
||||
|
@ -426,158 +419,6 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
None => String::new()
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
adw::ActionRow {
|
||||
set_title: &tr!("player-patch-version"),
|
||||
set_subtitle: &tr!("player-patch-version-description"),
|
||||
|
||||
add_suffix = >k::Label {
|
||||
#[watch]
|
||||
set_text: &match model.player_patch.as_ref() {
|
||||
Some(patch) => match patch.status() {
|
||||
PatchStatus::NotAvailable => tr!("patch-not-available"),
|
||||
|
||||
PatchStatus::Outdated { current, .. } => tr!("patch-outdated", {
|
||||
"current" = current.to_string()
|
||||
}),
|
||||
|
||||
PatchStatus::Preparation { .. } => tr!("patch-preparation"),
|
||||
|
||||
PatchStatus::Testing { version, .. } |
|
||||
PatchStatus::Available { version, .. } => version.to_string()
|
||||
}
|
||||
|
||||
None => String::from("?")
|
||||
},
|
||||
|
||||
#[watch]
|
||||
set_css_classes: match model.player_patch.as_ref() {
|
||||
Some(patch) => match patch.status() {
|
||||
PatchStatus::NotAvailable => &["error"],
|
||||
|
||||
PatchStatus::Outdated { .. } |
|
||||
PatchStatus::Preparation { .. } |
|
||||
PatchStatus::Testing { .. } => &["warning"],
|
||||
|
||||
PatchStatus::Available { .. } => unsafe {
|
||||
let path = match Config::get() {
|
||||
Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(),
|
||||
Err(_) => CONFIG.game.path.for_edition(CONFIG.launcher.edition).to_path_buf(),
|
||||
};
|
||||
|
||||
if let Ok(true) = model.player_patch.as_ref().unwrap_unchecked().is_applied(path) {
|
||||
&["success"]
|
||||
} else {
|
||||
&["warning"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None => &[]
|
||||
},
|
||||
|
||||
#[watch]
|
||||
set_tooltip_text: Some(&match model.player_patch.as_ref() {
|
||||
Some(patch) => match patch.status() {
|
||||
PatchStatus::NotAvailable => tr!("patch-not-available-tooltip"),
|
||||
|
||||
PatchStatus::Outdated { current, latest, .. } => tr!("patch-outdated-tooltip", {
|
||||
"current" = current.to_string(),
|
||||
"latest" = latest.to_string()
|
||||
}),
|
||||
|
||||
PatchStatus::Preparation { .. } => tr!("patch-preparation-tooltip"),
|
||||
PatchStatus::Testing { .. } => tr!("patch-testing-tooltip"),
|
||||
|
||||
PatchStatus::Available { .. } => unsafe {
|
||||
let path = match Config::get() {
|
||||
Ok(config) => config.game.path.for_edition(config.launcher.edition).to_path_buf(),
|
||||
Err(_) => CONFIG.game.path.for_edition(CONFIG.launcher.edition).to_path_buf(),
|
||||
};
|
||||
|
||||
if let Ok(true) = model.player_patch.as_ref().unwrap_unchecked().is_applied(path) {
|
||||
String::new()
|
||||
} else {
|
||||
tr!("patch-not-applied-tooltip")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None => String::new()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
add = &adw::PreferencesGroup {
|
||||
adw::ActionRow {
|
||||
set_title: &tr!("apply-main-patch"),
|
||||
set_subtitle: &tr!("apply-main-patch-description"),
|
||||
|
||||
add_suffix = >k::Switch {
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
set_state: CONFIG.patch.apply,
|
||||
|
||||
connect_state_notify[sender] => move |switch| {
|
||||
if is_ready() {
|
||||
#[allow(unused_must_use)]
|
||||
if let Ok(mut config) = Config::get() {
|
||||
config.patch.apply = switch.state();
|
||||
|
||||
Config::update(config);
|
||||
|
||||
sender.output(PreferencesAppMsg::UpdateLauncherState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
adw::ActionRow {
|
||||
set_title: &tr!("disable-mhypbase"),
|
||||
set_subtitle: &tr!("disable-mhypbase-description"),
|
||||
|
||||
add_suffix = >k::Switch {
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
set_state: CONFIG.patch.disable_mhypbase,
|
||||
|
||||
connect_state_notify[sender] => move |switch| {
|
||||
if is_ready() {
|
||||
#[allow(unused_must_use)]
|
||||
if let Ok(mut config) = Config::get() {
|
||||
config.patch.disable_mhypbase = switch.state();
|
||||
|
||||
Config::update(config);
|
||||
|
||||
sender.output(PreferencesAppMsg::UpdateLauncherState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
adw::ActionRow {
|
||||
set_title: &tr!("ask-superuser-permissions"),
|
||||
set_subtitle: &tr!("ask-superuser-permissions-description"),
|
||||
|
||||
add_suffix = >k::Switch {
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
set_state: CONFIG.patch.root,
|
||||
|
||||
connect_state_notify => |switch| {
|
||||
if is_ready() {
|
||||
if let Ok(mut config) = Config::get() {
|
||||
config.patch.root = switch.state();
|
||||
|
||||
Config::update(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -713,10 +554,7 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
.forward(sender.input_sender(), std::convert::identity),
|
||||
|
||||
game_diff: None,
|
||||
player_patch: None,
|
||||
|
||||
style: CONFIG.launcher.style,
|
||||
|
||||
languages: SUPPORTED_LANGUAGES.iter().map(|lang| tr!(format_lang(lang).as_str())).collect()
|
||||
};
|
||||
|
||||
|
@ -743,10 +581,6 @@ impl SimpleAsyncComponent for GeneralApp {
|
|||
self.game_diff = diff;
|
||||
}
|
||||
|
||||
GeneralAppMsg::SetPlayerPatch(patch) => {
|
||||
self.player_patch = patch;
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
GeneralAppMsg::AddVoicePackage(index) => {
|
||||
if let Some(package) = self.voice_packages.get(index.current_index()) {
|
||||
|
|
|
@ -4,7 +4,6 @@ use relm4::component::*;
|
|||
use gtk::prelude::*;
|
||||
use adw::prelude::*;
|
||||
|
||||
use anime_launcher_sdk::anime_game_core::prelude::*;
|
||||
use anime_launcher_sdk::anime_game_core::genshin::prelude::*;
|
||||
|
||||
use anime_launcher_sdk::config::ConfigExt;
|
||||
|
@ -28,11 +27,6 @@ pub enum PreferencesAppMsg {
|
|||
/// Supposed to be called automatically on app's run when the latest game version
|
||||
/// was retrieved from the API
|
||||
SetGameDiff(Option<VersionDiff>),
|
||||
|
||||
/// Supposed to be called automatically on app's run when the latest UnityPlayer patch version
|
||||
/// was retrieved from remote repos
|
||||
SetPlayerPatch(Option<PlayerPatch>),
|
||||
|
||||
SetLauncherStyle(LauncherStyle),
|
||||
|
||||
UpdateLauncherState,
|
||||
|
@ -119,11 +113,6 @@ impl SimpleAsyncComponent for PreferencesApp {
|
|||
self.general.sender().send(GeneralAppMsg::SetGameDiff(diff));
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
PreferencesAppMsg::SetPlayerPatch(patch) => {
|
||||
self.general.sender().send(GeneralAppMsg::SetPlayerPatch(patch));
|
||||
}
|
||||
|
||||
#[allow(unused_must_use)]
|
||||
PreferencesAppMsg::SetLauncherStyle(style) => {
|
||||
sender.output(Self::Output::SetLauncherStyle(style));
|
||||
|
|
Loading…
Add table
Reference in a new issue