modde_games/ue4/
scanner.rs1use anyhow::Result;
4
5use crate::scanner_patterns::FileGroupRule;
6use crate::traits::{DiscoveredMod, ModScanner, ScanContext};
7
8pub struct Ue4Scanner {
14 pub game_id: &'static str,
15 pub project_name: &'static str,
16}
17
18pub static STELLAR_BLADE_SCANNER: Ue4Scanner = Ue4Scanner {
19 game_id: "stellar-blade",
20 project_name: "SB",
21};
22
23pub static SUBNAUTICA2_SCANNER: Ue4Scanner = Ue4Scanner {
24 game_id: "subnautica2",
25 project_name: "Subnautica2",
26};
27
28const UE4_GROUP_EXTENSIONS: &[&str] = &["pak", "ucas", "utoc"];
29
30impl Ue4Scanner {
31 fn scan_subdir(
32 &self,
33 install: &std::path::Path,
34 subdir: &str,
35 location: &'static str,
36 out: &mut Vec<DiscoveredMod>,
37 ) {
38 let dir = install
39 .join(self.project_name)
40 .join("Content")
41 .join("Paks")
42 .join(subdir);
43 FileGroupRule {
44 rel_dir: "",
45 extensions: UE4_GROUP_EXTENSIONS,
46 mod_id_prefix: "pak",
47 source_location: location,
48 confidence: 0.9,
49 }
50 .scan_dir(install, &dir, out);
51 }
52}
53
54impl ModScanner for Ue4Scanner {
55 fn scan_directories(&self) -> &[&str] {
56 &["Content/Paks/~mods", "Content/Paks/LogicMods"]
59 }
60
61 fn scan_filesystem(&self, ctx: &ScanContext<'_>) -> Result<Vec<DiscoveredMod>> {
62 let mut out = Vec::new();
63 self.scan_subdir(ctx.install_dir, "~mods", "paks-mods", &mut out);
64 self.scan_subdir(ctx.install_dir, "LogicMods", "logic-mods", &mut out);
65 Ok(out)
66 }
67
68 fn mod_id_footprint(&self, mod_id: &str) -> Option<modde_core::scanner::ModFootprint> {
69 let stem = mod_id.strip_prefix("pak/")?.to_lowercase();
72 Some(modde_core::scanner::ModFootprint::File(format!(
73 "{}/content/paks/~mods/{stem}.pak",
74 self.project_name.to_lowercase()
75 )))
76 }
77}