From 43115cbac62ad1055479e2730c36adb2e82cb26e Mon Sep 17 00:00:00 2001
From: Quaternions <krakow20@gmail.com>
Date: Thu, 9 Nov 2023 15:51:23 -0800
Subject: [PATCH] mesh downloader

---
 src/main.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/src/main.rs b/src/main.rs
index 10ea31e..8b6d61f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,6 +15,7 @@ enum Commands {
     Download(MapList),
     DownloadTextures(PathBufList),
     ConvertTextures,
+    DownloadMeshes(PathBufList),
     Extract(PathBufList),
     Interactive,
     Replace,
@@ -97,6 +98,15 @@ fn get_texture_refs(dom:&rbx_dom_weak::WeakDom) -> Vec<rbx_dom_weak::types::Ref>
     //next class
     objects
 }
+fn get_mesh_refs(dom:&rbx_dom_weak::WeakDom) -> Vec<rbx_dom_weak::types::Ref>{
+    let mut objects = std::vec::Vec::new();
+    recursive_collect_superclass(&mut objects, dom, dom.root(),"FileMesh");
+    recursive_collect_superclass(&mut objects, dom, dom.root(),"MeshPart");
+    //get ids
+    //clear vec
+    //next class
+    objects
+}
 
 enum ReaderType<'a, R:Read+Seek>{
     GZip(flate2::read::GzDecoder<&'a mut R>),
@@ -336,6 +346,51 @@ fn download_textures(paths: Vec<std::path::PathBuf>) -> AResult<()>{
     }
     Ok(())
 }
+fn download_meshes(paths: Vec<std::path::PathBuf>) -> AResult<()>{
+    println!("download_meshes paths:{:?}",paths);
+    let header=format!("Cookie: .ROBLOSECURITY={}",std::env::var("RBXCOOKIE")?);
+    let shared_args=&[
+        "-q",
+        "--header",
+        header.as_str(),
+        "-O",
+    ];
+    let mut mesh_list=std::collections::HashSet::new();
+    for path in paths {
+        let mut input = std::io::BufReader::new(std::fs::File::open(path.clone())?);
+
+        match get_dom(&mut input){
+            Ok(dom)=>{
+                let object_refs = get_mesh_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("MeshId") {
+                            println!("Mesh content:{:?}",content);
+                            if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){
+                                mesh_list.insert(asset_id.0);
+                            }
+                        }
+                    }
+                }
+            },
+            Err(e)=>println!("error loading map {:?}: {:?}",path.file_name(),e),
+        }
+    }
+    println!("Mesh list:{:?}",mesh_list);
+    let processes_result:Result<Vec<_>, _>=mesh_list.iter().map(|asset_id|{
+        std::process::Command::new("wget")
+        .args(shared_args)
+        .arg(format!("meshes/unprocessed/{}",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!("Mesh exit_success:{}",output.status.success());
+    }
+    Ok(())
+}
 
 fn load_image<R:Read+Seek+std::io::BufRead>(input:&mut R)->AResult<image::DynamicImage>{
     let mut fourcc=[0u8;4];
@@ -912,6 +967,7 @@ fn main() -> AResult<()> {
         Commands::Download(map_list)=>download(map_list.maps),
         Commands::DownloadTextures(pathlist)=>download_textures(pathlist.paths),
         Commands::ConvertTextures=>convert_textures(),
+        Commands::DownloadMeshes(pathlist)=>download_meshes(pathlist.paths),
         Commands::Extract(pathlist)=>extract(pathlist.paths),
         Commands::Interactive=>interactive(),
         Commands::Replace=>replace(),