feat(star-rail): integrated jadeite patch

This commit is contained in:
Observer KRypt0n_ 2023-06-10 22:08:06 +02:00
parent 60d800a23d
commit 947b243245
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
4 changed files with 53 additions and 73 deletions

View file

@ -9,7 +9,7 @@ edition = "2021"
[dependencies.anime-game-core] [dependencies.anime-game-core]
git = "https://github.com/an-anime-team/anime-game-core" git = "https://github.com/an-anime-team/anime-game-core"
tag = "1.11.8" tag = "1.12.0"
features = ["all"] features = ["all"]
# path = "../anime-game-core" # ! for dev purposes only # path = "../anime-game-core" # ! for dev purposes only
@ -35,6 +35,10 @@ star-rail = ["anime-game-core/star-rail"]
honkai = ["anime-game-core/honkai"] honkai = ["anime-game-core/honkai"]
pgr = ["anime-game-core/pgr"] pgr = ["anime-game-core/pgr"]
genshin-patch = ["anime-game-core/patch-dawn"]
star-rail-patch = ["anime-game-core/patch-jadeite"]
honkai-patch = ["anime-game-core/patch-jadeite"]
# Common features # Common features
states = [] states = []
config = ["dep:serde", "dep:serde_json", "dep:enum-ordinalize"] config = ["dep:serde", "dep:serde_json", "dep:enum-ordinalize"]

View file

@ -7,9 +7,7 @@ use crate::star_rail::consts::launcher_dir;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Patch { pub struct Patch {
pub path: PathBuf, pub path: PathBuf
pub servers: Vec<String>,
pub root: bool
} }
impl Default for Patch { impl Default for Patch {
@ -18,15 +16,7 @@ impl Default for Patch {
let launcher_dir = launcher_dir().expect("Failed to get launcher dir"); let launcher_dir = launcher_dir().expect("Failed to get launcher dir");
Self { Self {
path: launcher_dir.join("patch"), path: launcher_dir.join("patch")
servers: vec![
String::from("https://codeberg.org/an-anime-team/astra"),
String::from("https://notabug.org/mkrsym1/astra")
],
// Disable root requirement for patching if we're running launcher in flatpak
root: !PathBuf::from("/.flatpak-info").exists()
} }
} }
} }
@ -36,35 +26,9 @@ impl From<&JsonValue> for Patch {
let default = Self::default(); let default = Self::default();
Self { Self {
path: match value.get("path") { path: match value.get("path").and_then(|path| path.as_str()).map(PathBuf::from) {
Some(value) => match value.as_str() { Some(path) => path,
Some(value) => PathBuf::from(value),
None => default.path None => default.path
},
None => default.path
},
servers: match value.get("servers") {
Some(value) => match value.as_array() {
Some(values) => {
let mut servers = Vec::new();
for value in values {
if let Some(server) = value.as_str() {
servers.push(server.to_string());
}
}
servers
},
None => default.servers
},
None => default.servers
},
root: match value.get("root") {
Some(value) => value.as_bool().unwrap_or(default.root),
None => default.root
} }
} }
} }

View file

@ -24,6 +24,7 @@ struct Folders {
pub wine: PathBuf, pub wine: PathBuf,
pub prefix: PathBuf, pub prefix: PathBuf,
pub game: PathBuf, pub game: PathBuf,
pub patch: PathBuf,
pub temp: PathBuf pub temp: PathBuf
} }
@ -34,6 +35,7 @@ fn replace_keywords(command: impl ToString, folders: &Folders) -> String {
.replace("%temp%", folders.game.to_str().unwrap()) .replace("%temp%", folders.game.to_str().unwrap())
.replace("%launcher%", &consts::launcher_dir().unwrap().to_string_lossy()) .replace("%launcher%", &consts::launcher_dir().unwrap().to_string_lossy())
.replace("%game%", folders.temp.to_str().unwrap()) .replace("%game%", folders.temp.to_str().unwrap())
.replace("%patch%", folders.patch.to_str().unwrap())
} }
/// Try to run the game /// Try to run the game
@ -60,6 +62,7 @@ pub fn run() -> anyhow::Result<()> {
wine: config.game.wine.builds.join(&wine.name), wine: config.game.wine.builds.join(&wine.name),
prefix: config.game.wine.prefix.clone(), prefix: config.game.wine.prefix.clone(),
game: game_path.clone(), game: game_path.clone(),
patch: config.patch.path.clone(),
temp: config.launcher.temp.clone().unwrap_or(std::env::temp_dir()) temp: config.launcher.temp.clone().unwrap_or(std::env::temp_dir())
}; };
@ -92,7 +95,7 @@ pub fn run() -> anyhow::Result<()> {
windows_command += " "; windows_command += " ";
} }
windows_command += "launch.bat "; windows_command += &format!("'{}/jadeite.exe' 'Z:\\{}/StarRail.exe' ", folders.patch.to_string_lossy(), folders.game.to_string_lossy());
if config.game.wine.borderless { if config.game.wine.borderless {
windows_command += "-screen-fullscreen 0 -popupwindow "; windows_command += "-screen-fullscreen 0 -popupwindow ";
@ -124,10 +127,13 @@ pub fn run() -> anyhow::Result<()> {
folders.game.to_str().unwrap() folders.game.to_str().unwrap()
); );
let bwrap = format!("{bwrap} --bind '{}' /tmp/sandbox/patch", folders.patch.to_string_lossy());
let sandboxed_folders = Folders { let sandboxed_folders = Folders {
wine: PathBuf::from("/tmp/sandbox/wine"), wine: PathBuf::from("/tmp/sandbox/wine"),
prefix: PathBuf::from("/tmp/sandbox/prefix"), prefix: PathBuf::from("/tmp/sandbox/prefix"),
game: PathBuf::from("/tmp/sandbox/game"), game: PathBuf::from("/tmp/sandbox/game"),
patch: PathBuf::from("/tmp/sandbox/patch"),
temp: PathBuf::from("/tmp") temp: PathBuf::from("/tmp")
}; };
@ -135,6 +141,14 @@ pub fn run() -> anyhow::Result<()> {
.replace(folders.wine.to_str().unwrap(), sandboxed_folders.wine.to_str().unwrap()) .replace(folders.wine.to_str().unwrap(), sandboxed_folders.wine.to_str().unwrap())
.replace(folders.prefix.to_str().unwrap(), sandboxed_folders.prefix.to_str().unwrap()) .replace(folders.prefix.to_str().unwrap(), sandboxed_folders.prefix.to_str().unwrap())
.replace(folders.game.to_str().unwrap(), sandboxed_folders.game.to_str().unwrap()) .replace(folders.game.to_str().unwrap(), sandboxed_folders.game.to_str().unwrap())
.replace(folders.patch.to_str().unwrap(), sandboxed_folders.patch.to_str().unwrap())
.replace(folders.temp.to_str().unwrap(), sandboxed_folders.temp.to_str().unwrap());
windows_command = windows_command
.replace(folders.wine.to_str().unwrap(), sandboxed_folders.wine.to_str().unwrap())
.replace(folders.prefix.to_str().unwrap(), sandboxed_folders.prefix.to_str().unwrap())
.replace(folders.game.to_str().unwrap(), sandboxed_folders.game.to_str().unwrap())
.replace(folders.patch.to_str().unwrap(), sandboxed_folders.patch.to_str().unwrap())
.replace(folders.temp.to_str().unwrap(), sandboxed_folders.temp.to_str().unwrap()); .replace(folders.temp.to_str().unwrap(), sandboxed_folders.temp.to_str().unwrap());
bash_command = format!("{bwrap} --chdir /tmp/sandbox/game -- {bash_command}"); bash_command = format!("{bwrap} --chdir /tmp/sandbox/game -- {bash_command}");

View file

@ -10,16 +10,21 @@ use crate::star_rail::config::Config;
pub enum LauncherState { pub enum LauncherState {
Launch, Launch,
/// Always contains `VersionDiff::Predownload` PatchNotVerified,
PredownloadAvailable(VersionDiff), PatchBroken,
PatchUnsafe,
MainPatchAvailable(MainPatch), PatchNotInstalled,
PatchUpdateAvailable,
#[cfg(feature = "components")] #[cfg(feature = "components")]
WineNotInstalled, WineNotInstalled,
PrefixNotExists, PrefixNotExists,
/// Always contains `VersionDiff::Predownload`
PredownloadAvailable(VersionDiff),
// Always contains `VersionDiff::Diff` // Always contains `VersionDiff::Diff`
GameUpdateAvailable(VersionDiff), GameUpdateAvailable(VersionDiff),
@ -42,8 +47,6 @@ pub struct LauncherStateParams<F: Fn(StateUpdating)> {
pub game_edition: GameEdition, pub game_edition: GameEdition,
pub wine_prefix: PathBuf, pub wine_prefix: PathBuf,
pub patch_servers: Vec<String>,
pub patch_folder: PathBuf, pub patch_folder: PathBuf,
pub status_updater: F pub status_updater: F
@ -65,29 +68,20 @@ impl LauncherState {
let diff = game.try_get_diff()?; let diff = game.try_get_diff()?;
match diff { match diff {
VersionDiff::Latest { .. } | VersionDiff::Predownload { .. } => { VersionDiff::Latest { version, .. } | VersionDiff::Predownload { current: version, .. } => {
// Check game patch status // Check game patch status
(params.status_updater)(StateUpdating::Patch); (params.status_updater)(StateUpdating::Patch);
let patch = Patch::new(&params.patch_folder, params.game_edition); if !jadeite::is_installed(&params.patch_folder) {
return Ok(Self::PatchNotInstalled);
// Sync local patch folder with remote if needed
// TODO: maybe I shouldn't do it here?
if patch.is_sync(&params.patch_servers)?.is_none() {
for server in &params.patch_servers {
if patch.sync(server).is_ok() {
break;
}
}
} }
// Check the main patch if jadeite::get_latest()?.version > jadeite::get_version(params.patch_folder)? {
let main_patch = patch.main_patch()?; return Ok(Self::PatchUpdateAvailable);
if !main_patch.is_applied(&params.game_path)? {
return Ok(Self::MainPatchAvailable(main_patch));
} }
match jadeite::get_metadata()?.hsr.global.get_status(version) {
JadeitePatchStatusVariant::Verified => {
// Check if update predownload available // Check if update predownload available
if let VersionDiff::Predownload { .. } = diff { if let VersionDiff::Predownload { .. } = diff {
Ok(Self::PredownloadAvailable(diff)) Ok(Self::PredownloadAvailable(diff))
@ -99,6 +93,12 @@ impl LauncherState {
} }
} }
JadeitePatchStatusVariant::Unverified => Ok(Self::PatchNotVerified),
JadeitePatchStatusVariant::Broken => Ok(Self::PatchBroken),
JadeitePatchStatusVariant::Unsafe => Ok(Self::PatchUnsafe)
}
}
VersionDiff::Diff { .. } => Ok(Self::GameUpdateAvailable(diff)), VersionDiff::Diff { .. } => Ok(Self::GameUpdateAvailable(diff)),
VersionDiff::Outdated { .. } => Ok(Self::GameOutdated(diff)), VersionDiff::Outdated { .. } => Ok(Self::GameOutdated(diff)),
VersionDiff::NotInstalled { .. } => Ok(Self::GameNotInstalled(diff)) VersionDiff::NotInstalled { .. } => Ok(Self::GameNotInstalled(diff))
@ -126,8 +126,6 @@ impl LauncherState {
game_edition: config.launcher.edition, game_edition: config.launcher.edition,
wine_prefix: config.get_wine_prefix_path(), wine_prefix: config.get_wine_prefix_path(),
patch_servers: config.patch.servers,
patch_folder: config.patch.path, patch_folder: config.patch.path,
status_updater status_updater