more texture sources + use asset tool to download meshes & textures

This commit is contained in:
Quaternions 2024-03-11 17:22:04 -07:00
parent 0172675b04
commit 95b6272b18

View File

@ -1,6 +1,7 @@
use std::{io::{Read, Seek}, path::PathBuf}; use std::{collections::HashSet,io::{Read,Seek},path::PathBuf};
use clap::{Args,Parser,Subcommand}; use clap::{Args,Parser,Subcommand};
use anyhow::Result as AResult; use anyhow::Result as AResult;
use rbx_dom_weak::Instance;
#[derive(Parser)] #[derive(Parser)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
@ -62,28 +63,6 @@ fn main() -> AResult<()> {
} }
} }
fn class_is_a(class: &str, superclass: &str) -> bool {
if class==superclass {
return true
}
let class_descriptor=rbx_reflection_database::get().classes.get(class);
if let Some(descriptor) = &class_descriptor {
if let Some(class_super) = &descriptor.superclass {
return class_is_a(&class_super, superclass)
}
}
false
}
fn recursive_collect_superclass(objects: &mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance, superclass: &str){
for &referent in instance.children() {
if let Some(c) = dom.get_by_ref(referent) {
if class_is_a(c.class.as_str(), superclass) {
objects.push(c.referent());//copy ref
}
recursive_collect_superclass(objects,dom,c,superclass);
}
}
}
fn recursive_collect_regex(objects: &mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance, regex: &lazy_regex::Lazy<lazy_regex::Regex>){ fn recursive_collect_regex(objects: &mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance, regex: &lazy_regex::Lazy<lazy_regex::Regex>){
for &referent in instance.children() { for &referent in instance.children() {
if let Some(c) = dom.get_by_ref(referent) { if let Some(c) = dom.get_by_ref(referent) {
@ -100,23 +79,6 @@ fn get_button_refs(dom:&rbx_dom_weak::WeakDom) -> Vec<rbx_dom_weak::types::Ref>{
recursive_collect_regex(&mut buttons, dom, dom.root(),lazy_regex::regex!(r"Button(\d+)$")); recursive_collect_regex(&mut buttons, dom, dom.root(),lazy_regex::regex!(r"Button(\d+)$"));
buttons buttons
} }
fn get_texture_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(),"Decal");
//get ids
//clear vec
//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>{ enum ReaderType<'a, R:Read+Seek>{
GZip(flate2::read::GzDecoder<&'a mut R>), GZip(flate2::read::GzDecoder<&'a mut R>),
@ -208,94 +170,99 @@ SurfaceAppearance.NormalMap
SurfaceAppearance.RoughnessMap SurfaceAppearance.RoughnessMap
SurfaceAppearance.TexturePack SurfaceAppearance.TexturePack
*/ */
fn accumulate_content_id(content_list:&mut HashSet<u64>,object:&Instance,property:&str){
if let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get(property){
if let Ok(asset_id)=AsRef::<str>::as_ref(content).parse::<RobloxAssetId>(){
content_list.insert(asset_id.0);
}else{
println!("Content failed to parse into AssetID: {:?}",content);
}
}else{
println!("property={} does not exist for class={}",object.class.as_str(),property);
}
}
fn download_textures(paths:Vec<PathBuf>)->AResult<()>{ fn download_textures(paths:Vec<PathBuf>)->AResult<()>{
println!("download_textures paths:{:?}",paths); println!("Reading files, this could take a hot minute...");
let header=format!("Cookie: .ROBLOSECURITY={}",std::env::var("RBXCOOKIE")?); let mut texture_list=HashSet::new();
let shared_args=&[
"-q",
"--header",
header.as_str(),
"-O",
];
let mut texture_list=std::collections::HashSet::new();
for path in paths{ for path in paths{
let mut input = std::io::BufReader::new(std::fs::File::open(path.clone())?); let file=match std::fs::File::open(path.as_path()){
Ok(file)=>file,
Err(e)=>{
println!("file error {e}");
continue;
}
};
let mut input=std::io::BufReader::new(file);
match get_dom(&mut input){ match get_dom(&mut input){
Ok(dom)=>{ Ok(dom)=>{
let object_refs = get_texture_refs(&dom); for object in dom.into_raw().1.into_values(){
for &object_ref in object_refs.iter() { match object.class.as_str(){
if let Some(object)=dom.get_by_ref(object_ref){ "Beam"=>accumulate_content_id(&mut texture_list,&object,"Texture"),
if let Some(rbx_dom_weak::types::Variant::Content(content)) = object.properties.get("Texture") { "Decal"=>accumulate_content_id(&mut texture_list,&object,"Texture"),
println!("Texture content:{:?}",content); "Texture"=>accumulate_content_id(&mut texture_list,&object,"Texture"),
if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){ "FileMesh"=>accumulate_content_id(&mut texture_list,&object,"TextureId"),
texture_list.insert(asset_id.0); "MeshPart"=>accumulate_content_id(&mut texture_list,&object,"TextureID"),
} "ParticleEmitter"=>accumulate_content_id(&mut texture_list,&object,"Texture"),
} "Sky"=>{
accumulate_content_id(&mut texture_list,&object,"MoonTextureId");
accumulate_content_id(&mut texture_list,&object,"SkyboxBk");
accumulate_content_id(&mut texture_list,&object,"SkyboxDn");
accumulate_content_id(&mut texture_list,&object,"SkyboxFt");
accumulate_content_id(&mut texture_list,&object,"SkyboxLf");
accumulate_content_id(&mut texture_list,&object,"SkyboxRt");
accumulate_content_id(&mut texture_list,&object,"SkyboxUp");
accumulate_content_id(&mut texture_list,&object,"SunTextureId");
},
_=>(),
} }
} }
}, },
Err(e)=>println!("error loading map {:?}: {:?}",path.file_name(),e), Err(e)=>println!("error loading map {:?}: {:?}",path.file_name(),e),
} }
} }
println!("Texture list:{:?}",texture_list); let texture_list_string=texture_list.into_iter().map(|id|id.to_string()).collect::<Vec<String>>();
let processes_result:Result<Vec<_>, _>=texture_list.iter().map(|asset_id|{ println!("Texture list:{:?}",texture_list_string.join(" "));
std::process::Command::new("wget") let output=std::process::Command::new("asset-tool")
.args(shared_args) .args(["download","environment","RBXCOOKIE","textures/unprocessed/"])
.arg(format!("textures/unprocessed/{}",asset_id)) .args(texture_list_string)
.arg(format!("https://assetdelivery.roblox.com/v1/asset/?ID={}",asset_id)) .spawn()?
.spawn() .wait_with_output()?;
}).collect(); println!("Asset tool exit_success:{}",output.status.success());
//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(()) Ok(())
} }
fn download_meshes(paths:Vec<PathBuf>)->AResult<()>{ fn download_meshes(paths:Vec<PathBuf>)->AResult<()>{
println!("download_meshes paths:{:?}",paths); println!("Reading files, this could take a hot minute...");
let header=format!("Cookie: .ROBLOSECURITY={}",std::env::var("RBXCOOKIE")?); let mut mesh_list=HashSet::new();
let shared_args=&[
"-q",
"--header",
header.as_str(),
"-O",
];
let mut mesh_list=std::collections::HashSet::new();
for path in paths{ for path in paths{
let mut input = std::io::BufReader::new(std::fs::File::open(path.clone())?); let file=match std::fs::File::open(path.as_path()){
Ok(file)=>file,
Err(e)=>{
println!("file error {e}");
continue;
}
};
let mut input=std::io::BufReader::new(file);
match get_dom(&mut input){ match get_dom(&mut input){
Ok(dom)=>{ Ok(dom)=>{
let object_refs = get_mesh_refs(&dom); for object in dom.into_raw().1.into_values(){
for &object_ref in object_refs.iter() { match object.class.as_str(){
if let Some(object)=dom.get_by_ref(object_ref){ "MeshPart"=>accumulate_content_id(&mut mesh_list,&object,"MeshId"),
if let Some(rbx_dom_weak::types::Variant::Content(content)) = object.properties.get("MeshId") { "SpecialMesh"=>accumulate_content_id(&mut mesh_list,&object,"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), Err(e)=>println!("error loading map {:?}: {:?}",path.file_name(),e),
} }
} }
println!("Mesh list:{:?}",mesh_list); let mesh_list_string=mesh_list.into_iter().map(|id|id.to_string()).collect::<Vec<String>>();
let processes_result:Result<Vec<_>, _>=mesh_list.iter().map(|asset_id|{ println!("Mesh list:{:?}",mesh_list_string.join(" "));
std::process::Command::new("wget") let output=std::process::Command::new("asset-tool")
.args(shared_args) .args(["download","environment","RBXCOOKIE","meshes/"])
.arg(format!("meshes/unprocessed/{}",asset_id)) .args(mesh_list_string)
.arg(format!("https://assetdelivery.roblox.com/v1/asset/?ID={}",asset_id)) .spawn()?
.spawn() .wait_with_output()?;
}).collect(); println!("Asset tool exit_success:{}",output.status.success());
//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(()) Ok(())
} }