feat(star-rail): integrated jadeite patch
This commit is contained in:
parent
60d800a23d
commit
947b243245
4 changed files with 53 additions and 73 deletions
|
@ -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"]
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}");
|
||||||
|
|
|
@ -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(¶ms.patch_folder, params.game_edition);
|
if !jadeite::is_installed(¶ms.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(¶ms.patch_servers)?.is_none() {
|
|
||||||
for server in ¶ms.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(¶ms.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
|
||||||
|
|
Loading…
Reference in a new issue