mirror of
https://github.com/redstrate/Physis.git
synced 2025-04-20 11:47:46 +00:00
Add game patch integration tests
Currently only the first two game patches are checked, eventually want to check boot patching as well. Hopefully this should weed out the remaining patching issues I encounter.
This commit is contained in:
parent
d87694df4d
commit
102c8901cf
4 changed files with 145 additions and 0 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -310,6 +310,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac-sha512"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a928b002dff1780b7fa21056991d395770ab9359154b8c1724c4d0511dad0a65"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
|
@ -464,12 +470,14 @@ dependencies = [
|
|||
"glam",
|
||||
"half 2.1.0",
|
||||
"hard-xml",
|
||||
"hmac-sha512",
|
||||
"libz-sys",
|
||||
"paste",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1_smol",
|
||||
"texpresso",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -16,10 +16,13 @@ name = "physis_benchmark"
|
|||
harness = false
|
||||
|
||||
[dev-dependencies]
|
||||
walkdir = "2"
|
||||
hmac-sha512 = "1.1.2"
|
||||
criterion = "0.4.0"
|
||||
|
||||
[features]
|
||||
retail_game_testing = []
|
||||
patch_testing = []
|
||||
|
||||
[dependencies]
|
||||
# used for jamcrc implementation, should eventually move away from it
|
||||
|
|
16
README.md
16
README.md
|
@ -43,6 +43,22 @@ Some tests and benchmarks require the environment variable `FFXIV_GAME_DIR` to b
|
|||
since they require a legitimate copy of the retail game data. These tests can be turned on via the `retail_game_testing`
|
||||
feature.
|
||||
|
||||
### Game Patch Testing
|
||||
|
||||
Patching is an extremely sensitive operation since it is not easily reversible if done wrong. Repairing the game files
|
||||
is also an option, but it's time-consuming and not yet implemented in physis. To prevent regressions in patching the
|
||||
game, I have set up a testing bed for cross-checking our implementation with others. Currently, this is limited to XIVLauncher's implementation,
|
||||
but I will eventually adopt a way to test the retail patch installer as well.
|
||||
|
||||
1. Enable the `patch_testing` feature.
|
||||
2. Set a couple of environment variables:
|
||||
* `FFXIV_PATCH_DIR` is the directory of patches to install. It should be structured as `$FFXIV_PATCH_DIR/game/D2017.07.11.0000.0001.patch`.
|
||||
* `FFXIV_XIV_LAUNCHER_PATCHER` should be the path to the patcher executable. If you're running on Linux, we will handle running Wine for you.
|
||||
* `FFXIV_INSTALLER` is the path to the installer executable. This will be installed using the usual InstallShield emulation physis already includes.
|
||||
|
||||
As you can see, you must have the previous patches downloaded first as well as the installer before running the tests.
|
||||
This is left up to the developer to figure out how to download them legally.
|
||||
|
||||
## Contributing & Support
|
||||
|
||||
The best way you can help is by [monetarily supporting me](https://redstrate.com/about/) or by submitting patches to help fix bugs or add functionality!
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
use physis::index;
|
||||
use std::env;
|
||||
use std::process::Command;
|
||||
use physis::installer::install_game;
|
||||
use physis::patch::apply_patch;
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(feature = "retail_game_testing"), ignore)]
|
||||
|
@ -23,3 +28,116 @@ fn test_gamedata_extract() {
|
|||
|
||||
assert!(gamedata.extract("exd/root.exl").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(feature = "patch_testing"), ignore)]
|
||||
fn test_patching() {
|
||||
let patch_dir = env::var("FFXIV_PATCH_DIR").unwrap();
|
||||
let patcher_exe = env::var("FFXIV_XIV_LAUNCHER_PATCHER").unwrap();
|
||||
let installer_exe = env::var("FFXIV_INSTALLER").unwrap();
|
||||
|
||||
println!("Beginning game installation...");
|
||||
|
||||
// FIXME: lmao what is going on here
|
||||
let mut game_dir = env::temp_dir();
|
||||
game_dir.push("game_test");
|
||||
|
||||
if std::fs::read_dir(&game_dir).ok().is_some() {
|
||||
std::fs::remove_dir_all(&game_dir).unwrap();
|
||||
}
|
||||
|
||||
std::fs::create_dir_all(&game_dir).unwrap();
|
||||
|
||||
install_game(&installer_exe, game_dir.as_path().to_str().unwrap()).ok().unwrap();
|
||||
|
||||
let mut xivlauncher_game_dir = env::temp_dir();
|
||||
xivlauncher_game_dir.push("game_test_xivlauncher");
|
||||
|
||||
if std::fs::read_dir(&xivlauncher_game_dir).ok().is_some() {
|
||||
std::fs::remove_dir_all(&xivlauncher_game_dir).unwrap();
|
||||
}
|
||||
std::fs::create_dir_all(&xivlauncher_game_dir).unwrap();
|
||||
|
||||
install_game(&installer_exe, xivlauncher_game_dir.as_path().to_str().unwrap()).ok().unwrap();
|
||||
|
||||
let xivlauncher_game_dir = xivlauncher_game_dir.as_path();
|
||||
let physis_game_dir = game_dir.as_path();
|
||||
|
||||
// TODO: only the first two patches are checked
|
||||
let patches = ["game/D2017.07.11.0000.0001.patch",
|
||||
"game/D2017.09.24.0000.0001.patch"];
|
||||
|
||||
println!("The game installation is now complete. Now testing game patching...");
|
||||
|
||||
// run it on xiv's patchinstaller first
|
||||
// TODO: check for windows systems
|
||||
for patch in patches {
|
||||
let patch_path = format!("Z:\\{}\\{}", patch_dir, &patch);
|
||||
let game_dir = format!("Z:\\{}\\game", xivlauncher_game_dir.to_str().unwrap());
|
||||
|
||||
let output = Command::new("/usr/bin/wine")
|
||||
.args([&patcher_exe,
|
||||
"install",
|
||||
&patch_path,
|
||||
&game_dir])
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
println!("{:#?}", output);
|
||||
}
|
||||
|
||||
// now run it on physis
|
||||
for patch in patches {
|
||||
let patch_path = format!("{}/{}", patch_dir, &patch);
|
||||
let data_dir = format!("{}/{}", physis_game_dir.to_str().unwrap(), "game");
|
||||
|
||||
apply_patch(&data_dir, &patch_path).unwrap();
|
||||
}
|
||||
|
||||
println!("Game patching is now complete. Proceeding to checksum matching...");
|
||||
|
||||
let mut xivlauncher_files : HashMap<String, [u8; 64]> = HashMap::new();
|
||||
|
||||
println!("{:#?}", xivlauncher_game_dir);
|
||||
|
||||
// TODO: consolidate into a closure or generic function
|
||||
WalkDir::new(xivlauncher_game_dir)
|
||||
.into_iter()
|
||||
.filter_map(Result::ok)
|
||||
.filter(|e| !e.file_type().is_dir())
|
||||
.for_each(|x| {
|
||||
let file = std::fs::read(x.path()).unwrap();
|
||||
|
||||
let mut hash = hmac_sha512::Hash::new();
|
||||
hash.update(&file);
|
||||
let sha = hash.finalize();
|
||||
|
||||
let mut rel_path = x.path();
|
||||
rel_path = rel_path.strip_prefix(xivlauncher_game_dir).unwrap();
|
||||
|
||||
xivlauncher_files.insert(rel_path.to_str().unwrap().to_string(), sha);
|
||||
});
|
||||
|
||||
let mut physis_files : HashMap<String, [u8; 64]> = HashMap::new();
|
||||
|
||||
WalkDir::new(physis_game_dir)
|
||||
.into_iter()
|
||||
.filter_map(Result::ok)
|
||||
.filter(|e| !e.file_type().is_dir())
|
||||
.for_each(|x| {
|
||||
if !x.file_type().is_dir() {
|
||||
let file = std::fs::read(x.path()).unwrap();
|
||||
|
||||
let mut hash = hmac_sha512::Hash::new();
|
||||
hash.update(&file);
|
||||
let sha = hash.finalize();
|
||||
|
||||
let mut rel_path = x.path();
|
||||
rel_path = rel_path.strip_prefix(physis_game_dir).unwrap();
|
||||
|
||||
physis_files.insert(rel_path.to_str().unwrap().to_string(), sha);
|
||||
}
|
||||
});
|
||||
|
||||
assert_eq!(physis_files, xivlauncher_files);
|
||||
}
|
Loading…
Add table
Reference in a new issue