From a1c23d92deb28ac5971f7e0aa34cabea429d740f Mon Sep 17 00:00:00 2001 From: Danny Bierek Date: Tue, 11 Jun 2024 01:29:18 -0700 Subject: [PATCH] Move to library and examples --- Cargo.lock | 428 ++++++++++++++++++++++++++++++++++- Cargo.toml | 2 + examples/connect_to_game.rs | 27 +++ examples/scan_scenario.rs | 16 ++ src/lib.rs | 1 + src/main.rs | 220 +----------------- src/scanner/mod.rs | 1 + src/scanner/scenario_scan.rs | 253 +++++++++++++++++++++ 8 files changed, 728 insertions(+), 220 deletions(-) create mode 100644 examples/connect_to_game.rs create mode 100644 examples/scan_scenario.rs create mode 100644 src/lib.rs create mode 100644 src/scanner/mod.rs create mode 100644 src/scanner/scenario_scan.rs diff --git a/Cargo.lock b/Cargo.lock index 82a93e4..a703070 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "binrw" version = "0.13.3" @@ -56,6 +62,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -77,6 +92,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + [[package]] name = "cc" version = "1.0.98" @@ -89,6 +110,31 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -124,13 +170,22 @@ dependencies = [ "typenum", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", + "block-buffer 0.10.4", "crypto-common", ] @@ -146,6 +201,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "extended-tea" version = "0.1.1" @@ -155,6 +220,33 @@ dependencies = [ "byteorder", ] +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -174,6 +266,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "glacier2obj" version = "0.1.0" @@ -194,6 +297,8 @@ dependencies = [ "serde-hex", "serde_json", "thiserror", + "tungstenite", + "url", "version-sync", ] @@ -203,6 +308,23 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3935c160d00ac752e09787e6e6bfc26494c2183cc922f1bc678a60d4733bc2" + [[package]] name = "idna" version = "0.5.0" @@ -267,6 +389,18 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + [[package]] name = "lz4" version = "1.24.0" @@ -300,7 +434,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -339,6 +473,23 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -351,6 +502,56 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "owo-colors" version = "3.5.0" @@ -369,6 +570,18 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.85" @@ -398,6 +611,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rayon" version = "1.10.0" @@ -469,12 +712,57 @@ dependencies = [ "thiserror", ] +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.23" @@ -532,6 +820,19 @@ dependencies = [ "serde", ] +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "smallvec" version = "0.6.14" @@ -569,6 +870,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys", +] + [[package]] name = "thiserror" version = "1.0.61" @@ -638,6 +951,26 @@ dependencies = [ "winnow", ] +[[package]] +name = "tungstenite" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "native-tls", + "rand", + "sha-1", + "thiserror", + "url", + "utf-8", +] + [[package]] name = "typenum" version = "1.17.0" @@ -685,6 +1018,18 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-sync" version = "0.9.5" @@ -706,6 +1051,85 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + [[package]] name = "winnow" version = "0.5.40" diff --git a/Cargo.toml b/Cargo.toml index 718a2d8..fff9f70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ byteorder = "1.5.0" rayon = { version = "1.10.0", optional = true} serde = { version = "1.0.199", optional = true, features = ["derive"] } serde-hex = { version = "0.1.0", optional = true } +tungstenite = { version = "0.16.0", features = ["native-tls"]} +url = "2.2.2" [features] default = ["path-list", "serde"] diff --git a/examples/connect_to_game.rs b/examples/connect_to_game.rs new file mode 100644 index 0000000..43ac8eb --- /dev/null +++ b/examples/connect_to_game.rs @@ -0,0 +1,27 @@ +use std::env; + +use tungstenite::{connect, Message}; +use url::Url; + +pub fn main() { + let args: Vec = env::args().collect(); + if args.len() < 2 { + eprintln!("Usage: cargo run -- example connect_to_game "); + return; + } + println!("Connecting to game on port {}", args[1]); + + let (mut socket, _response) = connect( + Url::parse(("ws://localhost:".to_string() + &args[1] + "/socket").as_str()).unwrap() + ).expect("Can't connect"); + + let _ = socket.write_message(Message::Text(r#"{"type":"hello","identifier":"glacier2obj"}"#.into())); + // let desk = "feeda4e80bc4b859"; + // let _ = socket.write_message(Message::Text(r#"{"type":"selectEntity","entity":{"id": "feede50ae0479660","tblu":"003FC5B5BE3EA0CE"}}"#.into())); + let _ = socket.write_message(Message::Text(r#"{"type":"listEntities"}"#.into())); + + loop { + let msg = socket.read_message().expect("Error reading message"); + println!("Received: {}", msg); + } +} diff --git a/examples/scan_scenario.rs b/examples/scan_scenario.rs new file mode 100644 index 0000000..bc45c14 --- /dev/null +++ b/examples/scan_scenario.rs @@ -0,0 +1,16 @@ +use std::env; + +use glacier2obj::scanner::scenario_scan::ScenarioScan; + +// Based on mount_game_files example from rpkg-rs +pub fn main() { + let args: Vec = env::args().collect(); + if args.len() < 6 { + eprintln!("Usage: cargo run -- example scan_scenario "); + return; + } + let mut scan: ScenarioScan = ScenarioScan::new(args[1].clone(), args[2].clone(), args[3].clone(), args[4].clone()); + scan.scan_scenario(); + scan.output_to_file(args[5].clone()); + return; +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..1c967b5 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1 @@ +pub mod scanner; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index d25cc91..71ebc89 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,223 +1,7 @@ -use itertools::Itertools; -use rpkg_rs::misc::hash_path_list::PathList; -use rpkg_rs::misc::ini_file_system::IniFileSystem; -use rpkg_rs::misc::resource_id::ResourceID; -use rpkg_rs::resource::partition_manager::{PartitionManager, PartitionState}; -use rpkg_rs::resource::pdefs::PackageDefinitionSource; -use rpkg_rs::resource::resource_info::ResourceInfo; -use rpkg_rs::resource::resource_partition::PatchId; -use rpkg_rs::resource::runtime_resource_id::RuntimeResourceID; -use std::collections::{HashSet, VecDeque}; -use std::io::Write; -use std::path::{Path, PathBuf}; -use std::str::FromStr; -use std::{env, io}; +use std::env; // Based on mount_game_files example from rpkg-rs pub fn main() { let args: Vec = env::args().collect(); - if args.len() < 5 { - eprintln!("Usage: cargo run "); - return; - } - - let retail_path = PathBuf::from(&args[1]); - let thumbs_path = retail_path.join("thumbs.dat"); - - let thumbs = IniFileSystem::from(&thumbs_path.as_path()).unwrap_or_else(|err| { - eprintln!("Error reading thumbs file: {:?}", err); - std::process::exit(1); - }); - - let app_options = &thumbs.root()["application"]; - - let hash_list_path = Path::new(&args[4]); - - let mut path_list = PathList::new(); - path_list.parse_into(hash_list_path).unwrap(); - - - if let (Some(proj_path), Some(relative_runtime_path)) = ( - app_options.options().get("PROJECT_PATH"), - app_options.options().get("RUNTIME_PATH"), - ) { - let runtime_path = PathBuf::from(format!( - "{}\\{proj_path}\\{relative_runtime_path}", - retail_path.display() - )); - std::println!("start reading package definitions {:?}", runtime_path); - - let mut package_manager = PartitionManager::new(runtime_path.clone()); - - //read the packagedefs here - let mut last_index = 0; - let mut progress = 0.0; - let progress_callback = |current, state: &PartitionState| { - if current != last_index { - last_index = current; - print!("Mounting partition {} ", current); - } - let install_progress = (state.install_progress * 10.0).ceil() / 10.0; - - let chars_to_add = (install_progress * 10.0 - progress * 10.0) as usize * 2; - let chars_to_add = std::cmp::min(chars_to_add, 20); - print!("{}", "█".repeat(chars_to_add)); - io::stdout().flush().unwrap(); - - progress = install_progress; - - if progress == 1.0 { - progress = 0.0; - println!(" done :)"); - } - }; - - let package_defs_bytes = - std::fs::read(runtime_path.join("packagedefinition.txt").as_path()).unwrap(); - - let mut package_defs = match args[2].as_str() { - "HM2016" => PackageDefinitionSource::HM2016(package_defs_bytes).read(), - "HM2" => PackageDefinitionSource::HM2(package_defs_bytes).read(), - "HM3" => PackageDefinitionSource::HM3(package_defs_bytes).read(), - e => { - eprintln!("invalid game version: {}", e); - std::process::exit(0); - } - } - .unwrap_or_else(|e| { - println!("Failed to parse package definitions {}", e); - std::process::exit(0); - }); - - //ignore modded patches - for partition in package_defs.iter_mut() { - partition.set_max_patch_level(301); - } - - package_manager - .mount_partitions( - PackageDefinitionSource::Custom(package_defs), - progress_callback, - ) - .unwrap_or_else(|e| { - eprintln!("failed to init package manager: {}", e); - std::process::exit(0); - }); - - let ioi_string_or_hash = args[3].as_str(); - let mut hash; - let hash_resource_id = RuntimeResourceID::from_hex_string(ioi_string_or_hash); - if hash_resource_id.is_err() { - let ioi_string_resource_id = ResourceID::from_str(ioi_string_or_hash); - if !ioi_string_resource_id.is_err() { - hash = RuntimeResourceID::from_resource_id(&ioi_string_resource_id.unwrap()).to_hex_string(); - } else { - println!("Invalid RuntimeResourceId"); - std::process::exit(0); - } - } else { - hash = ioi_string_or_hash.to_string(); - } - let mut hashes: VecDeque = VecDeque::from([String::from_str(&hash).unwrap()]); - let mut found_hashes = HashSet::new(); - println!("Getting ALOCs for: {}", hash); - loop { - if hashes.len() == 0 { - break; - } - hash = hashes.pop_front().unwrap(); - let rrid = RuntimeResourceID::from_hex_string(&hash).unwrap_or_else(|_| { - println!("Invalid RuntimeResourceId"); - std::process::exit(0); - }); - if found_hashes.contains(&rrid) { - continue; - } - found_hashes.insert(rrid); - let resource_package_opt = get_resource_info(&package_manager, &rrid); - if resource_package_opt.is_none() { - continue; - } - let ioi_string = if path_list.get(&rrid).is_some() { - path_list.get(&rrid).unwrap().resource_path() - } else { - "".to_string() - }; - - let resource_package = resource_package_opt.unwrap(); - let references = resource_package.0.references(); - // println!("{} {} Type: {} Partition: {}", rrid, ioi_string, resource_package.0.data_type(), resource_package.1); - - for reference in references.iter() { - let dep_rrid = reference.0; - - if found_hashes.contains(&dep_rrid) { - continue; - } - let depend_resource_opt = get_resource_info(&package_manager, &dep_rrid); - if depend_resource_opt.is_none() { - continue; - } - let dep_ioi_string = if path_list.get(&dep_rrid).is_some() { - path_list.get(&dep_rrid).unwrap().resource_path() - } else { - "".to_string() - }; - - let depend_resource = depend_resource_opt.unwrap(); - if Vec::from(["TEMP", "ALOC", "PRIM"]).contains(&depend_resource.0.data_type().as_str()) { - let is_aloc = depend_resource.0.data_type().as_str() == "ALOC"; - // println!("|-> {} {} Type: {} Partition: {}", dep_rrid, dep_ioi_string, depend_resource.0.data_type(), depend_resource.1); - - if is_aloc { - println!("{} {} Type: {} Partition: {}", rrid, ioi_string, resource_package.0.data_type(), resource_package.1); - - println!("|-> {} {} Type: {} Partition: {}", dep_rrid, dep_ioi_string, depend_resource.0.data_type(), depend_resource.1); - } - hashes.push_back(dep_rrid.to_hex_string()); - } - } - } - } else { - eprintln!( - "Missing required properties inside thumbs.dat:\n\ - PROJECT_PATH: {}\n\ - RUNTIME_PATH: {}", - app_options.has_option("PROJECT_PATH"), - app_options.has_option("RUNTIME_PATH") - ); - return; - } -} - -fn get_resource_info(package_manager: &PartitionManager, rrid: &RuntimeResourceID) -> Option<(ResourceInfo, String)> { - let mut last_occurrence: Option<&ResourceInfo> = None; - let mut last_partition: Option = None; - for partition in package_manager.partitions() { - let changes = partition.resource_patch_indices(rrid); - let deletions = partition.resource_removal_indices(rrid); - let occurrences = changes - .clone() - .into_iter() - .chain(deletions.clone().into_iter()) - .collect::>(); - for occurrence in occurrences.iter().sorted() { - if deletions.contains(occurrence) { - last_occurrence = None; - } - if changes.contains(occurrence) { - if let Ok(info) = partition.resource_info_from(rrid, *occurrence) { - last_occurrence = Some(info); - last_partition = Some(partition.partition_info().filename(*occurrence)); - } - } - } - if !last_occurrence.is_none(){ - break; - } - } - if last_occurrence.is_none() || last_partition.is_none() { - return None - } - return Some((last_occurrence.unwrap().clone(), last_partition.unwrap())); } + \ No newline at end of file diff --git a/src/scanner/mod.rs b/src/scanner/mod.rs new file mode 100644 index 0000000..86e3cc8 --- /dev/null +++ b/src/scanner/mod.rs @@ -0,0 +1 @@ +pub mod scenario_scan; \ No newline at end of file diff --git a/src/scanner/scenario_scan.rs b/src/scanner/scenario_scan.rs new file mode 100644 index 0000000..ba51ae3 --- /dev/null +++ b/src/scanner/scenario_scan.rs @@ -0,0 +1,253 @@ +use itertools::Itertools; +use rpkg_rs::misc::hash_path_list::PathList; +use rpkg_rs::misc::ini_file_system::IniFileSystem; +use rpkg_rs::misc::resource_id::ResourceID; +use rpkg_rs::resource::partition_manager::{PartitionManager, PartitionState}; +use rpkg_rs::resource::pdefs::PackageDefinitionSource; +use rpkg_rs::resource::resource_info::ResourceInfo; +use rpkg_rs::resource::resource_partition::PatchId; +use rpkg_rs::resource::runtime_resource_id::RuntimeResourceID; +use std::collections::{HashSet, VecDeque}; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::str::FromStr; +use std::{fs, io}; + +pub struct ScenarioScan { + retail_folder: String, + game_version: String, + scenario: String, + hash_list_file: String, + hashes_for_output: HashSet, + alocs_for_output: HashSet, + +} + +impl ScenarioScan { + pub fn new(retail_folder: String, game_version: String, scenario: String, hash_list_file: String) -> Self { + Self { + retail_folder, + game_version, + scenario, + hash_list_file, + hashes_for_output: HashSet::new(), + alocs_for_output: HashSet::new(), + } + } + + pub fn scan_scenario(&mut self) { + let retail_path = PathBuf::from(&self.retail_folder); + let thumbs_path = retail_path.join("thumbs.dat"); + + let thumbs = IniFileSystem::from(&thumbs_path.as_path()).unwrap_or_else(|err| { + eprintln!("Error reading thumbs file: {:?}", err); + std::process::exit(1); + }); + + let app_options = &thumbs.root()["application"]; + + let hash_list_path = Path::new(&self.hash_list_file); + + let mut path_list = PathList::new(); + path_list.parse_into(hash_list_path).unwrap(); + + + if let (Some(proj_path), Some(relative_runtime_path)) = ( + app_options.options().get("PROJECT_PATH"), + app_options.options().get("RUNTIME_PATH"), + ) { + let runtime_path = PathBuf::from(format!( + "{}\\{proj_path}\\{relative_runtime_path}", + retail_path.display() + )); + std::println!("start reading package definitions {:?}", runtime_path); + + let mut package_manager = PartitionManager::new(runtime_path.clone()); + + //read the packagedefs here + let mut last_index = 0; + let mut progress = 0.0; + let progress_callback = |current, state: &PartitionState| { + if current != last_index { + last_index = current; + print!("Mounting partition {} ", current); + } + let install_progress = (state.install_progress * 10.0).ceil() / 10.0; + + let chars_to_add = (install_progress * 10.0 - progress * 10.0) as usize * 2; + let chars_to_add = std::cmp::min(chars_to_add, 20); + print!("{}", "█".repeat(chars_to_add)); + io::stdout().flush().unwrap(); + + progress = install_progress; + + if progress == 1.0 { + progress = 0.0; + println!(" done :)"); + } + }; + + let package_defs_bytes = + std::fs::read(runtime_path.join("packagedefinition.txt").as_path()).unwrap(); + + let mut package_defs = match self.game_version.as_str() { + "HM2016" => PackageDefinitionSource::HM2016(package_defs_bytes).read(), + "HM2" => PackageDefinitionSource::HM2(package_defs_bytes).read(), + "HM3" => PackageDefinitionSource::HM3(package_defs_bytes).read(), + e => { + eprintln!("invalid game version: {}", e); + std::process::exit(0); + } + } + .unwrap_or_else(|e| { + println!("Failed to parse package definitions {}", e); + std::process::exit(0); + }); + + //ignore modded patches + for partition in package_defs.iter_mut() { + partition.set_max_patch_level(301); + } + + package_manager + .mount_partitions( + PackageDefinitionSource::Custom(package_defs), + progress_callback, + ) + .unwrap_or_else(|e| { + eprintln!("failed to init package manager: {}", e); + std::process::exit(0); + }); + + let ioi_string_or_hash = self.scenario.as_str(); + let mut hash; + let hash_resource_id = RuntimeResourceID::from_hex_string(ioi_string_or_hash); + if hash_resource_id.is_err() { + let ioi_string_resource_id = ResourceID::from_str(ioi_string_or_hash); + if !ioi_string_resource_id.is_err() { + hash = RuntimeResourceID::from_resource_id(&ioi_string_resource_id.unwrap()).to_hex_string(); + } else { + println!("Invalid RuntimeResourceId"); + std::process::exit(0); + } + } else { + hash = ioi_string_or_hash.to_string(); + } + let mut hashes: VecDeque = VecDeque::from([String::from_str(&hash).unwrap()]); + let mut found_hashes = HashSet::new(); + println!("Getting ALOCs for: {}", hash); + loop { + if hashes.len() == 0 { + break; + } + hash = hashes.pop_front().unwrap(); + let rrid = RuntimeResourceID::from_hex_string(&hash).unwrap_or_else(|_| { + println!("Invalid RuntimeResourceId"); + std::process::exit(0); + }); + if found_hashes.contains(&rrid) { + continue; + } + found_hashes.insert(rrid); + let resource_package_opt = ScenarioScan::get_resource_info(&package_manager, &rrid); + if resource_package_opt.is_none() { + continue; + } + let ioi_string = if path_list.get(&rrid).is_some() { + path_list.get(&rrid).unwrap().resource_path() + } else { + "".to_string() + }; + + let resource_package = resource_package_opt.unwrap(); + let references = resource_package.0.references(); + // println!("{} {} Type: {} Partition: {}", rrid, ioi_string, resource_package.0.data_type(), resource_package.1); + + for reference in references.iter() { + let dep_rrid = reference.0; + + if found_hashes.contains(&dep_rrid) { + continue; + } + let depend_resource_opt = ScenarioScan::get_resource_info(&package_manager, &dep_rrid); + if depend_resource_opt.is_none() { + continue; + } + let dep_ioi_string = if path_list.get(&dep_rrid).is_some() { + path_list.get(&dep_rrid).unwrap().resource_path() + } else { + "".to_string() + }; + + let depend_resource = depend_resource_opt.unwrap(); + if Vec::from(["TEMP", "ALOC", "PRIM"]).contains(&depend_resource.0.data_type().as_str()) { + let is_aloc = depend_resource.0.data_type().as_str() == "ALOC"; + if is_aloc { + println!("{} {} Type: {} Partition: {}", rrid, ioi_string, resource_package.0.data_type(), resource_package.1); + println!("|-> {} {} Type: {} Partition: {}", dep_rrid, dep_ioi_string, depend_resource.0.data_type(), depend_resource.1); + self.hashes_for_output.insert(rrid); + self.alocs_for_output.insert(dep_rrid); + } + hashes.push_back(dep_rrid.to_hex_string()); + + } + } + } + } else { + eprintln!( + "Missing required properties inside thumbs.dat:\n\ + PROJECT_PATH: {}\n\ + RUNTIME_PATH: {}", + app_options.has_option("PROJECT_PATH"), + app_options.has_option("RUNTIME_PATH") + ); + return; + } + } + + pub fn output_to_file(&self, output_file: String) { + let output_path = Path::new(&output_file); + let mut data = String::from("{\"ToFind\":["); + let mut it = self.hashes_for_output.iter().peekable(); + while let Some(rrid) = it.next() { + data += (String::from("\"") + rrid.to_hex_string().as_str() + "\"").as_str(); + if it.peek().is_some() { + data += String::from(",").as_str(); + } + } + data += String::from("]}").as_str(); + fs::write(output_path, data).expect("Unable to write file"); + } + + fn get_resource_info(package_manager: &PartitionManager, rrid: &RuntimeResourceID) -> Option<(ResourceInfo, String)> { + let mut last_occurrence: Option<&ResourceInfo> = None; + let mut last_partition: Option = None; + for partition in package_manager.partitions() { + let changes = partition.resource_patch_indices(rrid); + let deletions = partition.resource_removal_indices(rrid); + let occurrences = changes + .clone() + .into_iter() + .chain(deletions.clone().into_iter()) + .collect::>(); + for occurrence in occurrences.iter().sorted() { + if deletions.contains(occurrence) { + last_occurrence = None; + } + if changes.contains(occurrence) { + if let Ok(info) = partition.resource_info_from(rrid, *occurrence) { + last_occurrence = Some(info); + last_partition = Some(partition.partition_info().filename(*occurrence)); + } + } + } + if !last_occurrence.is_none(){ + break; + } + } + if last_occurrence.is_none() || last_partition.is_none() { + return None + } + return Some((last_occurrence.unwrap().clone(), last_partition.unwrap())); + } +} \ No newline at end of file