From 34b6a869f03d2390f57575cf5c365dafd9a87899 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Fri, 22 Sep 2023 14:24:28 -0700 Subject: [PATCH] add download textures command --- Cargo.lock | 45 +++++++++++++++++++++++++ Cargo.toml | 1 + src/main.rs | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index a03cc49..037e932 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.5.0" @@ -270,8 +279,15 @@ dependencies = [ "rbx_binary", "rbx_dom_weak", "rbx_reflection_database", + "regex", ] +[[package]] +name = "memchr" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" + [[package]] name = "num-traits" version = "0.2.16" @@ -423,6 +439,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + [[package]] name = "rmp" version = "0.8.12" diff --git a/Cargo.toml b/Cargo.toml index ffefc67..162d1ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ clap = { version = "4.4.2", features = ["derive"] } rbx_binary = "0.7.1" rbx_dom_weak = "2.5.0" rbx_reflection_database = "0.2.7" +regex = "1.9.5" [profile.release] lto = true diff --git a/src/main.rs b/src/main.rs index d9fc3c2..1a8a5bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ struct Cli { #[derive(Subcommand)] enum Commands { Download(MapList), + DownloadTextures(PathBufList), Upload, Scan, Extract(PathBufList), @@ -92,6 +93,14 @@ fn get_script_refs(dom:&rbx_dom_weak::WeakDom) -> Vec{ recursive_collect_superclass(&mut scripts, dom, dom.root(),"LuaSourceContainer"); scripts } +fn get_texture_refs(dom:&rbx_dom_weak::WeakDom) -> Vec{ + let mut objects = std::vec::Vec::new(); + recursive_collect_superclass(&mut objects, dom, dom.root(),"Decal"); + //get ids + //clear vec + //next class + objects +} fn get_id() -> BoxResult{ match std::fs::read_to_string("id"){ @@ -196,6 +205,92 @@ fn download(map_list: Vec) -> BoxResult<()>{ Ok(()) } +struct RobloxAssetId(u64); +struct RobloxAssetIdParseErr; +impl std::str::FromStr for RobloxAssetId { + type Err=RobloxAssetIdParseErr; + fn from_str(s: &str) -> Result{ + let regman=regex::Regex::new(r"(\d+)$").unwrap(); + if let Some(captures) = regman.captures(s) { + if captures.len()==2{//captures[0] is all captures concatenated, and then each individual capture + if let Ok(id) = captures[0].parse::() { + return Ok(Self(id)); + } + } + } + Err(RobloxAssetIdParseErr) + } +} +/* The ones I'm interested in: +Beam.Texture +Decal.Texture +FileMesh.MeshId +FileMesh.TextureId +MaterialVariant.ColorMap +MaterialVariant.MetalnessMap +MaterialVariant.NormalMap +MaterialVariant.RoughnessMap +MeshPart.MeshId +MeshPart.TextureID +ParticleEmitter.Texture +Sky.MoonTextureId +Sky.SkyboxBk +Sky.SkyboxDn +Sky.SkyboxFt +Sky.SkyboxLf +Sky.SkyboxRt +Sky.SkyboxUp +Sky.SunTextureId +SurfaceAppearance.ColorMap +SurfaceAppearance.MetalnessMap +SurfaceAppearance.NormalMap +SurfaceAppearance.RoughnessMap +SurfaceAppearance.TexturePack +*/ +fn download_textures(paths: Vec) -> BoxResult<()>{ + println!("download_textures paths:{:?}",paths); + let header=format!("Cookie: .ROBLOSECURITY={}",std::env::var("RBXCOOKIE")?); + let shared_args=&[ + "-q", + "--header", + header.as_str(), + "-O", + ]; + let mut texture_list=std::collections::HashSet::new(); + for path in paths { + let input = std::io::BufReader::new(std::fs::File::open(path)?); + + let dom = rbx_binary::from_reader(input)?; + + let object_refs = get_texture_refs(&dom); + + for &object_ref in object_refs.iter() { + if let Some(object)=dom.get_by_ref(object_ref){ + if let Some(rbx_dom_weak::types::Variant::Content(content)) = object.properties.get("Texture") { + println!("Texture content:{:?}",content); + if let Ok(asset_id)=content.clone().into_string().parse::(){ + texture_list.insert(asset_id.0); + } + } + } + } + } + println!("Texture list:{:?}",texture_list); + let processes_result:Result, _>=texture_list.iter().map(|asset_id|{ + std::process::Command::new("wget") + .args(shared_args) + .arg(format!("textures/{}",asset_id)) + .arg(format!("https://assetdelivery.roblox.com/v1/asset/?ID={}",asset_id)) + .spawn() + }).collect(); + //naively wait for all because idk how to make an async progress bar lmao + for child in processes_result?{ + let output=child.wait_with_output()?; + println!("texture exit_success:{}",output.status.success()); + } + Ok(()) +} + enum Scan{ Passed, Blocked, @@ -651,6 +746,7 @@ fn main() -> BoxResult<()> { let cli = Cli::parse(); match cli.command { Commands::Download(map_list)=>download(map_list.maps), + Commands::DownloadTextures(pathlist)=>download_textures(pathlist.paths), Commands::Upload=>upload(), Commands::Scan=>scan(), Commands::Replace=>replace(),