From 084facb5aba2087152a0bf17ba9bbd8ed5ea91ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Tue, 15 Aug 2023 16:24:24 +0800 Subject: [PATCH] Implement split uexp/uasset lint --- src/mod_lint.rs | 66 ++++++++++++++++-- test_assets/lints/split_uasset_uexp.pak | Bin 0 -> 579 bytes .../split_uasset_uexp/missing_uasset/a.uexp | 0 .../split_uasset_uexp/missing_uexp/b.uasset | 0 tests/lint/mod.rs | 34 ++++++++- 5 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 test_assets/lints/split_uasset_uexp.pak create mode 100644 test_assets/lints/split_uasset_uexp/missing_uasset/a.uexp create mode 100644 test_assets/lints/split_uasset_uexp/missing_uexp/b.uasset diff --git a/src/mod_lint.rs b/src/mod_lint.rs index b31d6817..9e7c900e 100644 --- a/src/mod_lint.rs +++ b/src/mod_lint.rs @@ -9,6 +9,12 @@ use tracing::{info, span, trace, Level}; use crate::providers::ModSpecification; use crate::{lint_get_all_files_from_data, open_file, GetAllFilesFromDataError, PakOrNotPak}; +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum SplitUasset { + MissingUasset, + MissingUexp, +} + #[derive(Debug, Clone)] pub struct ModLintReport { pub conflicting_mods: BTreeMap)>>, @@ -19,6 +25,7 @@ pub struct ModLintReport { pub archive_with_only_non_pak_files_mods: BTreeSet, pub archive_with_multiple_paks_mods: BTreeSet, pub non_asset_file_mods: BTreeMap>, + pub split_uasset_uexp_mods: BTreeMap>, } pub fn lint(mods: &[(ModSpecification, PathBuf)]) -> Result { @@ -36,6 +43,8 @@ pub fn lint(mods: &[(ModSpecification, PathBuf)]) -> Result { let mut empty_archive_mods = BTreeSet::new(); let mut archive_with_multiple_paks_mods = BTreeSet::new(); let mut non_asset_file_mods = BTreeMap::new(); + let mut path_extensions_map: BTreeMap> = BTreeMap::new(); + let mut split_uasset_uexp_mods = BTreeMap::new(); for (mod_spec, mod_pak_path) in mods { trace!(?mod_spec, ?mod_pak_path); @@ -95,10 +104,7 @@ pub fn lint(mods: &[(ModSpecification, PathBuf)]) -> Result { || lowercase.ends_with("assetregistry.bin") || lowercase.ends_with(".ushaderbytecode")) { - trace!( - "file is not known unreal asset: `{}`", - lowercase - ); + trace!("file is not known unreal asset: `{}`", lowercase); non_asset_file_mods .entry(mod_spec.clone()) .and_modify(|files: &mut BTreeSet| { @@ -107,6 +113,21 @@ pub fn lint(mods: &[(ModSpecification, PathBuf)]) -> Result { .or_insert_with(|| [lowercase.clone()].into()); } + path_extensions_map + .entry(p.clone()) + .and_modify(|extensions| { + if let Some(ext) = p.rsplit('.').next() { + extensions.insert(ext.to_string()); + } + }) + .or_insert_with(|| { + if let Some(ext) = p.rsplit('.').next() { + [ext.to_string()].into() + } else { + BTreeSet::default() + } + }); + let mut buf = vec![]; let mut writer = Cursor::new(&mut buf); pak.read_file(&p, &mut pak_bufs[0].1, &mut writer)?; @@ -146,6 +167,42 @@ pub fn lint(mods: &[(ModSpecification, PathBuf)]) -> Result { } } } + + path_extensions_map + .iter() + .for_each(|(path_without_ext, exts)| { + match (exts.contains("uasset"), exts.contains("uexp")) { + (true, false) => { + split_uasset_uexp_mods + .entry(mod_spec.clone()) + .and_modify( + |mismatched_pairs_map: &mut BTreeMap| { + mismatched_pairs_map + .insert(path_without_ext.clone(), SplitUasset::MissingUexp); + }, + ) + .or_insert_with(|| { + [(path_without_ext.clone(), SplitUasset::MissingUexp)].into() + }); + } + (false, true) => { + split_uasset_uexp_mods + .entry(mod_spec.clone()) + .and_modify( + |mismatched_pairs_map: &mut BTreeMap| { + mismatched_pairs_map.insert( + path_without_ext.clone(), + SplitUasset::MissingUasset, + ); + }, + ) + .or_insert_with(|| { + [(path_without_ext.clone(), SplitUasset::MissingUasset)].into() + }); + } + _ => {} + } + }); } const CONFLICTING_MODS_LINT_WHITELIST: [&str; 1] = ["fsd/content/_interop"]; @@ -189,5 +246,6 @@ pub fn lint(mods: &[(ModSpecification, PathBuf)]) -> Result { archive_with_only_non_pak_files_mods, archive_with_multiple_paks_mods, non_asset_file_mods, + split_uasset_uexp_mods, }) } diff --git a/test_assets/lints/split_uasset_uexp.pak b/test_assets/lints/split_uasset_uexp.pak new file mode 100644 index 0000000000000000000000000000000000000000..d2ae7cba3f9e029f2c5a29d09d09980ad136c3eb GIT binary patch literal 579 zcmZQzzzuF$E`Ar6?agZxy8r#u1c?djZ?JRXRt=TGsfi1yKu=E}f*6>P3}OVbzd-p4 zF!9t&Dwn7BC+&Zlwm3nKMWNzaqYOx$2#5fJAPB{*Fo;hMyAdis(Y{5><^r@ zN&+JH0ICE;JupS$fb9Nk?GdB0F3zpQ$w~Z-{nlU$j4Vdl6jIAY}jmHE~cc literal 0 HcmV?d00001 diff --git a/test_assets/lints/split_uasset_uexp/missing_uasset/a.uexp b/test_assets/lints/split_uasset_uexp/missing_uasset/a.uexp new file mode 100644 index 00000000..e69de29b diff --git a/test_assets/lints/split_uasset_uexp/missing_uexp/b.uasset b/test_assets/lints/split_uasset_uexp/missing_uexp/b.uasset new file mode 100644 index 00000000..e69de29b diff --git a/tests/lint/mod.rs b/tests/lint/mod.rs index de5ce8ad..6586290e 100644 --- a/tests/lint/mod.rs +++ b/tests/lint/mod.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::str::FromStr; -use drg_mod_integration::mod_lint::ModLintReport; +use drg_mod_integration::mod_lint::{ModLintReport, SplitUasset}; use drg_mod_integration::providers::ModSpecification; #[test] @@ -215,3 +215,35 @@ pub fn test_lint_non_asset_files() { Some(&["never_gonna_let_you_down.txt".to_string()].into()) ); } + +#[test] +pub fn test_lint_split_uasset_uexp_pairs() { + let base_path = PathBuf::from_str("test_assets/lints/").unwrap(); + assert!(base_path.exists()); + let split_uasset_uexp_pak_path = base_path.clone().join("split_uasset_uexp.pak"); + assert!(split_uasset_uexp_pak_path.exists()); + + let split_uasset_uexp_spec = ModSpecification { + url: "split_uasset_uexp".to_string(), + }; + + let mods = vec![(split_uasset_uexp_spec.clone(), split_uasset_uexp_pak_path)]; + + let ModLintReport { + split_uasset_uexp_mods, + .. + } = drg_mod_integration::mod_lint::lint(&mods).unwrap(); + + println!("{:#?}", split_uasset_uexp_mods); + + assert_eq!( + split_uasset_uexp_mods.get(&split_uasset_uexp_spec), + Some( + &[ + ("missing_uasset/a.uexp".to_string(), SplitUasset::MissingUasset), + ("missing_uexp/b.uasset".to_string(), SplitUasset::MissingUexp) + ] + .into() + ) + ); +}