feat: removed patch integration

This commit is contained in:
Observer KRypt0n_ 2023-08-17 11:54:39 +02:00
parent db3dc481f6
commit 252c948073
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
14 changed files with 36 additions and 575 deletions

16
Cargo.lock generated
View file

@ -39,8 +39,8 @@ dependencies = [
[[package]] [[package]]
name = "anime-game-core" name = "anime-game-core"
version = "1.13.5" version = "1.15.0"
source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.13.5#11e48e47563acf97a6885d3cc369875031dc5f61" source = "git+https://github.com/an-anime-team/anime-game-core?tag=1.15.0#e34a35e04dd97d8268e47769f82591100b3354ae"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bzip2", "bzip2",
@ -88,8 +88,8 @@ dependencies = [
[[package]] [[package]]
name = "anime-launcher-sdk" name = "anime-launcher-sdk"
version = "1.8.13" version = "1.10.0"
source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.8.13#1669dceafce3eaa3e9332fb4ac6ff78ea9fb1639" source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.10.0#916d4b56e0de0b3ed7720603da2090cbd9a11210"
dependencies = [ dependencies = [
"anime-game-core", "anime-game-core",
"anyhow", "anyhow",
@ -1288,9 +1288,9 @@ dependencies = [
[[package]] [[package]]
name = "glib-build-tools" name = "glib-build-tools"
version = "0.17.10" version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a65d79efe318ef2cbbbb37032b125866fd82c34ea44c816132621bbc552e716" checksum = "3431c56f463443cba9bc3600248bc6d680cb614c2ee1cdd39dab5415bd12ac5c"
[[package]] [[package]]
name = "glib-macros" name = "glib-macros"
@ -1971,9 +1971,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]] [[package]]
name = "open" name = "open"
version = "4.2.0" version = "5.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a083c0c7e5e4a8ec4176346cf61f67ac674e8bfb059d9226e1c54a96b377c12" checksum = "cfabf1927dce4d6fdf563d63328a0a506101ced3ec780ca2135747336c98cef8"
dependencies = [ dependencies = [
"is-wsl", "is-wsl",
"libc", "libc",

View file

@ -15,12 +15,12 @@ lto = true
opt-level = "s" opt-level = "s"
[build-dependencies] [build-dependencies]
glib-build-tools = "0.17" glib-build-tools = "0.18"
[dependencies.anime-launcher-sdk] [dependencies.anime-launcher-sdk]
git = "https://github.com/an-anime-team/anime-launcher-sdk" git = "https://github.com/an-anime-team/anime-launcher-sdk"
tag = "1.8.13" tag = "1.10.0"
features = ["all", "genshin", "genshin-patch"] features = ["all", "genshin"]
# path = "../anime-launcher-sdk" # ! for dev purposes only # 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"] } adw = { package = "libadwaita", version = "0.4", features = ["v1_2"] }
rfd = { version = "0.11", features = ["xdg-portal"], default-features = false } rfd = { version = "0.11", features = ["xdg-portal"], default-features = false }
open = "4.0" open = "5.0.0"
whatadistro = "0.1.0" whatadistro = "0.1.0"
serde_json = "1.0" serde_json = "1.0"

View file

@ -209,13 +209,10 @@ fn main() {
return; return;
} }
LauncherState::PredownloadAvailable { .. } | LauncherState::PredownloadAvailable { .. } if just_run_game => {
LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status: PatchStatus::NotAvailable, .. }, .. } => { anime_launcher_sdk::genshin::game::run().expect("Failed to run the game");
if just_run_game {
anime_launcher_sdk::genshin::game::run().expect("Failed to run the game");
return; return;
}
} }
_ => () _ => ()

View file

@ -25,7 +25,6 @@ pub struct DefaultPathsApp {
game_china: PathBuf, game_china: PathBuf,
fps_unlocker: PathBuf, fps_unlocker: PathBuf,
components: PathBuf, components: PathBuf,
patch: PathBuf,
temp: PathBuf temp: PathBuf
} }
@ -39,7 +38,6 @@ pub enum Folders {
GameChina, GameChina,
FpsUnlocker, FpsUnlocker,
Components, Components,
Patch,
Temp Temp
} }
@ -194,17 +192,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
connect_activated => DefaultPathsAppMsg::ChoosePath(Folders::Components) 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 { adw::ActionRow {
set_title: &tr!("temp-folder"), set_title: &tr!("temp-folder"),
set_icon_name: Some("folder-symbolic"), set_icon_name: Some("folder-symbolic"),
@ -302,7 +289,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
game_china: CONFIG.game.path.china.clone(), game_china: CONFIG.game.path.china.clone(),
fps_unlocker: CONFIG.game.enhancements.fps_unlocker.path.clone(), fps_unlocker: CONFIG.game.enhancements.fps_unlocker.path.clone(),
components: CONFIG.components.path.clone(), components: CONFIG.components.path.clone(),
patch: CONFIG.patch.path.clone(),
#[allow(clippy::or_fun_call)] #[allow(clippy::or_fun_call)]
temp: CONFIG.launcher.temp.clone().unwrap_or(std::env::temp_dir()) 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.game_china = result.join(concat!("Yu", "anS", "hen"));
self.fps_unlocker = result.join("fps-unlocker"); self.fps_unlocker = result.join("fps-unlocker");
self.components = result.join("components"); self.components = result.join("components");
self.patch = result.join("patch");
self.temp = result.clone(); self.temp = result.clone();
self.launcher = result; self.launcher = result;
@ -350,7 +335,6 @@ impl SimpleAsyncComponent for DefaultPathsApp {
Folders::GameChina => self.game_china = result, Folders::GameChina => self.game_china = result,
Folders::FpsUnlocker => self.fps_unlocker = result, Folders::FpsUnlocker => self.fps_unlocker = result,
Folders::Components => self.components = result, Folders::Components => self.components = result,
Folders::Patch => self.patch = result,
Folders::Temp => self.temp = 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.global, &self.game_global),
(old_config.game.path.china, &self.game_china), (old_config.game.path.china, &self.game_china),
(old_config.components.path, &self.components), (old_config.components.path, &self.components),
(old_config.patch.path, &self.patch),
(old_config.game.enhancements.fps_unlocker.path, &self.fps_unlocker) (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.global = self.game_global.clone();
config.game.path.china = self.game_china.clone(); config.game.path.china = self.game_china.clone();
config.components.path = self.components.clone(); config.components.path = self.components.clone();
config.patch.path = self.patch.clone();
config.launcher.temp = Some(self.temp.clone()); config.launcher.temp = Some(self.temp.clone());
config.game.enhancements.fps_unlocker.path = self.fps_unlocker.clone(); config.game.enhancements.fps_unlocker.path = self.fps_unlocker.clone();

View file

@ -9,7 +9,6 @@ use anime_launcher_sdk::components::loader::ComponentsLoader;
use crate::*; use crate::*;
use super::welcome::*; use super::welcome::*;
use super::tos_warning::*;
use super::dependencies::*; use super::dependencies::*;
use super::default_paths::*; use super::default_paths::*;
use super::select_voiceovers::*; use super::select_voiceovers::*;
@ -22,7 +21,6 @@ pub static mut MAIN_WINDOW: Option<adw::ApplicationWindow> = None;
pub struct FirstRunApp { pub struct FirstRunApp {
welcome: AsyncController<WelcomeApp>, welcome: AsyncController<WelcomeApp>,
tos_warning: AsyncController<TosWarningApp>,
dependencies: AsyncController<DependenciesApp>, dependencies: AsyncController<DependenciesApp>,
default_paths: AsyncController<DefaultPathsApp>, default_paths: AsyncController<DefaultPathsApp>,
select_voiceovers: AsyncController<SelectVoiceoversApp>, select_voiceovers: AsyncController<SelectVoiceoversApp>,
@ -40,7 +38,6 @@ pub struct FirstRunApp {
pub enum FirstRunAppMsg { pub enum FirstRunAppMsg {
SetLoadingStatus(Option<Option<String>>), SetLoadingStatus(Option<Option<String>>),
ScrollToTosWarning,
ScrollToDependencies, ScrollToDependencies,
ScrollToDefaultPaths, ScrollToDefaultPaths,
ScrollToSelectVoiceovers, ScrollToSelectVoiceovers,
@ -100,7 +97,6 @@ impl SimpleComponent for FirstRunApp {
set_allow_scroll_wheel: false, set_allow_scroll_wheel: false,
append = model.welcome.widget(), append = model.welcome.widget(),
append = model.tos_warning.widget(),
append = model.dependencies.widget(), append = model.dependencies.widget(),
append = model.default_paths.widget(), append = model.default_paths.widget(),
append = model.select_voiceovers.widget(), append = model.select_voiceovers.widget(),
@ -135,10 +131,6 @@ impl SimpleComponent for FirstRunApp {
.launch(()) .launch(())
.forward(sender.input_sender(), std::convert::identity), .forward(sender.input_sender(), std::convert::identity),
tos_warning: TosWarningApp::builder()
.launch(())
.forward(sender.input_sender(), std::convert::identity),
dependencies: DependenciesApp::builder() dependencies: DependenciesApp::builder()
.launch(()) .launch(())
.forward(sender.input_sender(), std::convert::identity), .forward(sender.input_sender(), std::convert::identity),
@ -190,12 +182,6 @@ impl SimpleComponent for FirstRunApp {
self.loading = status; self.loading = status;
} }
FirstRunAppMsg::ScrollToTosWarning => {
self.title = tr!("tos-violation-warning");
self.carousel.scroll_to(self.tos_warning.widget(), true);
}
FirstRunAppMsg::ScrollToDependencies => { FirstRunAppMsg::ScrollToDependencies => {
self.title = tr!("dependencies"); self.title = tr!("dependencies");

View file

@ -1,6 +1,5 @@
pub mod main; pub mod main;
pub mod welcome; pub mod welcome;
pub mod tos_warning;
pub mod dependencies; pub mod dependencies;
pub mod default_paths; pub mod default_paths;
pub mod select_voiceovers; pub mod select_voiceovers;

View file

@ -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()
}
}
}

View file

@ -3,6 +3,8 @@ use relm4::component::*;
use adw::prelude::*; use adw::prelude::*;
use anime_launcher_sdk::is_available;
use crate::*; use crate::*;
use super::main::FirstRunAppMsg; use super::main::FirstRunAppMsg;
@ -83,7 +85,11 @@ impl SimpleAsyncComponent for WelcomeApp {
match msg { match msg {
#[allow(unused_must_use)] #[allow(unused_must_use)]
WelcomeAppMsg::Continue => { 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);
}
} }
} }
} }

View file

@ -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
});
});
}
}
}

View file

@ -1,4 +1,5 @@
use std::process::Command; use std::process::Command;
use std::path::PathBuf;
use relm4::prelude::*; use relm4::prelude::*;
@ -19,7 +20,12 @@ pub fn disable_telemetry(sender: ComponentSender<App>) {
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(" ; "); .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") Command::new("pkexec")
.arg("bash") .arg("bash")
.arg("-c") .arg("-c")

View file

@ -11,7 +11,6 @@ use adw::prelude::*;
use gtk::glib::clone; use gtk::glib::clone;
mod repair_game; mod repair_game;
mod apply_patch;
mod download_wine; mod download_wine;
mod create_prefix; mod create_prefix;
mod download_diff; mod download_diff;
@ -79,10 +78,6 @@ pub enum AppMsg {
/// was retrieved from the API /// was retrieved from the API
SetGameDiff(Option<VersionDiff>), 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 /// Supposed to be called automatically on app's run when the launcher state was chosen
SetLauncherState(Option<LauncherState>), SetLauncherState(Option<LauncherState>),
@ -418,15 +413,6 @@ impl SimpleComponent for App {
Some(LauncherState::VoiceUpdateAvailable(_)) | Some(LauncherState::VoiceUpdateAvailable(_)) |
Some(LauncherState::VoiceNotInstalled(_)) => "document-save-symbolic", 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::TelemetryNotDisabled) => "security-high-symbolic",
Some(LauncherState::VoiceOutdated(_)) | Some(LauncherState::VoiceOutdated(_)) |
@ -440,8 +426,6 @@ impl SimpleComponent for App {
Some(LauncherState::PredownloadAvailable { .. }) => tr!("launch"), Some(LauncherState::PredownloadAvailable { .. }) => tr!("launch"),
Some(LauncherState::FolderMigrationRequired { .. }) => tr!("migrate-folders"), Some(LauncherState::FolderMigrationRequired { .. }) => tr!("migrate-folders"),
Some(LauncherState::PlayerPatchAvailable { .. }) => tr!("apply-patch"),
Some(LauncherState::TelemetryNotDisabled) => tr!("disable-telemetry"), Some(LauncherState::TelemetryNotDisabled) => tr!("disable-telemetry"),
Some(LauncherState::WineNotInstalled) => tr!("download-wine"), Some(LauncherState::WineNotInstalled) => tr!("download-wine"),
@ -480,17 +464,7 @@ impl SimpleComponent for App {
Some(LauncherState::GameOutdated { .. }) | Some(LauncherState::GameOutdated { .. }) |
Some(LauncherState::VoiceOutdated(_)) => false, 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, Some(_) => true,
None => false None => false
}, },
@ -499,17 +473,7 @@ impl SimpleComponent for App {
Some(LauncherState::GameOutdated { .. }) | Some(LauncherState::GameOutdated { .. }) |
Some(LauncherState::VoiceOutdated(_)) => &["warning", "pill"], 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"], Some(_) => &["suggested-action", "pill"],
None => &["pill"] None => &["pill"]
}, },
@ -520,15 +484,6 @@ impl SimpleComponent for App {
Some(LauncherState::FolderMigrationRequired { .. }) => tr!("migrate-folders-tooltip"), 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() _ => 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 // Update initial game version status
tasks.push(std::thread::spawn(clone!(@strong sender => move || { tasks.push(std::thread::spawn(clone!(@strong sender => move || {
@ -1045,10 +945,6 @@ impl SimpleComponent for App {
"locale" = locale.to_name() "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)); 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) => { AppMsg::SetLauncherState(state) => {
self.state = state; self.state = state;
} }
@ -1174,16 +1065,12 @@ impl SimpleComponent for App {
AppMsg::PerformAction => unsafe { AppMsg::PerformAction => unsafe {
match self.state.as_ref().unwrap_unchecked() { match self.state.as_ref().unwrap_unchecked() {
LauncherState::PlayerPatchAvailable { patch: PlayerPatch { status: PatchStatus::NotAvailable, .. }, .. } |
LauncherState::PredownloadAvailable { .. } | LauncherState::PredownloadAvailable { .. } |
LauncherState::Launch => launch::launch(sender), LauncherState::Launch => launch::launch(sender),
LauncherState::FolderMigrationRequired { from, to, cleanup_folder } => LauncherState::FolderMigrationRequired { from, to, cleanup_folder } =>
migrate_folder::migrate_folder(sender, from.to_owned(), to.to_owned(), cleanup_folder.to_owned()), 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::TelemetryNotDisabled => disable_telemetry::disable_telemetry(sender),
LauncherState::WineNotInstalled => download_wine::download_wine(sender, self.progress_bar.sender().to_owned()), LauncherState::WineNotInstalled => download_wine::download_wine(sender, self.progress_bar.sender().to_owned()),

View file

@ -1,5 +1,3 @@
use std::path::Path;
use relm4::{ use relm4::{
prelude::*, prelude::*,
Sender 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()))); 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() { 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) { if let Err(err) = file.repair(&game_path) {
sender.input(AppMsg::Toast { sender.input(AppMsg::Toast {
title: tr!("game-file-repairing-error"), title: tr!("game-file-repairing-error"),
description: Some(err.to_string()) description: Some(err.to_string())
}); });
tracing::error!("Failed to repair game file: {err}"); tracing::error!("Failed to repair game file: {err}");
}
}
else {
tracing::debug!("Skipped file: {}", file.path.to_string_lossy());
} }
progress_bar_input.send(ProgressBarMsg::UpdateProgress(i as u64 + 1, total)); progress_bar_input.send(ProgressBarMsg::UpdateProgress(i as u64 + 1, total));

View file

@ -111,10 +111,7 @@ pub struct GeneralApp {
components_page: AsyncController<ComponentsPage>, components_page: AsyncController<ComponentsPage>,
game_diff: Option<VersionDiff>, game_diff: Option<VersionDiff>,
player_patch: Option<PlayerPatch>,
style: LauncherStyle, style: LauncherStyle,
languages: Vec<String> languages: Vec<String>
} }
@ -124,10 +121,6 @@ pub enum GeneralAppMsg {
/// was retrieved from the API /// was retrieved from the API
SetGameDiff(Option<VersionDiff>), 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 // If one ever wish to change it to accept VoiceLocale
// I'd recommend to use clone!(@strong self.locale as locale => move |_| { .. }) // I'd recommend to use clone!(@strong self.locale as locale => move |_| { .. })
// in the VoicePackage component // in the VoicePackage component
@ -426,158 +419,6 @@ impl SimpleAsyncComponent for GeneralApp {
None => String::new() None => String::new()
}) })
} }
},
adw::ActionRow {
set_title: &tr!("player-patch-version"),
set_subtitle: &tr!("player-patch-version-description"),
add_suffix = &gtk::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 = &gtk::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 = &gtk::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 = &gtk::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), .forward(sender.input_sender(), std::convert::identity),
game_diff: None, game_diff: None,
player_patch: None,
style: CONFIG.launcher.style, style: CONFIG.launcher.style,
languages: SUPPORTED_LANGUAGES.iter().map(|lang| tr!(format_lang(lang).as_str())).collect() 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; self.game_diff = diff;
} }
GeneralAppMsg::SetPlayerPatch(patch) => {
self.player_patch = patch;
}
#[allow(unused_must_use)] #[allow(unused_must_use)]
GeneralAppMsg::AddVoicePackage(index) => { GeneralAppMsg::AddVoicePackage(index) => {
if let Some(package) = self.voice_packages.get(index.current_index()) { if let Some(package) = self.voice_packages.get(index.current_index()) {

View file

@ -4,7 +4,6 @@ use relm4::component::*;
use gtk::prelude::*; use gtk::prelude::*;
use adw::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::anime_game_core::genshin::prelude::*;
use anime_launcher_sdk::config::ConfigExt; 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 /// Supposed to be called automatically on app's run when the latest game version
/// was retrieved from the API /// was retrieved from the API
SetGameDiff(Option<VersionDiff>), 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), SetLauncherStyle(LauncherStyle),
UpdateLauncherState, UpdateLauncherState,
@ -119,11 +113,6 @@ impl SimpleAsyncComponent for PreferencesApp {
self.general.sender().send(GeneralAppMsg::SetGameDiff(diff)); 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)] #[allow(unused_must_use)]
PreferencesAppMsg::SetLauncherStyle(style) => { PreferencesAppMsg::SetLauncherStyle(style) => {
sender.output(Self::Output::SetLauncherStyle(style)); sender.output(Self::Output::SetLauncherStyle(style));