wip download_assets (pre-tokio)

This commit is contained in:
Quaternions 2025-01-27 08:47:51 -08:00
parent 349cd9c233
commit a5079f21d7

@ -1,5 +1,5 @@
use std::path::PathBuf; use std::path::{Path,PathBuf};
use std::io::{Read,Seek}; use std::io::{Cursor,Read,Seek};
use std::collections::HashSet; use std::collections::HashSet;
use clap::{Args,Subcommand}; use clap::{Args,Subcommand};
use anyhow::Result as AResult; use anyhow::Result as AResult;
@ -9,8 +9,7 @@ use strafesnet_deferred_loader::rbxassetid::RobloxAssetId;
#[derive(Subcommand)] #[derive(Subcommand)]
pub enum Commands{ pub enum Commands{
RobloxToSNF(RobloxToSNFSubcommand), RobloxToSNF(RobloxToSNFSubcommand),
DownloadTextures(DownloadTexturesSubcommand), DownloadAssets(DownloadAssetsSubcommand),
DownloadMeshes(DownloadMeshesSubcommand),
} }
#[derive(Args)] #[derive(Args)]
@ -21,12 +20,7 @@ pub struct RobloxToSNFSubcommand {
input_files:Vec<PathBuf>, input_files:Vec<PathBuf>,
} }
#[derive(Args)] #[derive(Args)]
pub struct DownloadTexturesSubcommand { pub struct DownloadAssetsSubcommand{
#[arg(long,required=true)]
roblox_files:Vec<PathBuf>
}
#[derive(Args)]
pub struct DownloadMeshesSubcommand {
#[arg(long,required=true)] #[arg(long,required=true)]
roblox_files:Vec<PathBuf> roblox_files:Vec<PathBuf>
} }
@ -35,27 +29,19 @@ impl Commands{
pub fn run(self)->AResult<()>{ pub fn run(self)->AResult<()>{
match self{ match self{
Commands::RobloxToSNF(subcommand)=>roblox_to_snf(subcommand.input_files,subcommand.output_folder), Commands::RobloxToSNF(subcommand)=>roblox_to_snf(subcommand.input_files,subcommand.output_folder),
Commands::DownloadTextures(subcommand)=>download_textures(subcommand.roblox_files), Commands::DownloadAssets(subcommand)=>download_assets(subcommand.roblox_files),
Commands::DownloadMeshes(subcommand)=>download_meshes(subcommand.roblox_files),
} }
} }
} }
fn load_dom<R:Read+Seek>(input:&mut R)->AResult<rbx_dom_weak::WeakDom>{ fn load_dom<R:Read+Seek>(mut input:R)->AResult<rbx_dom_weak::WeakDom>{
let mut first_8=[0u8;8]; let mut first_8=[0u8;8];
if let (Ok(()),Ok(()))=(std::io::Read::read_exact(input, &mut first_8),std::io::Seek::rewind(input)){ input.read_exact(&mut first_8)?;
match &first_8[0..4]{ input.rewind()?;
b"<rob"=>{ match &first_8{
match &first_8[4..8]{ b"<roblox!"=>rbx_binary::from_reader(input).map_err(anyhow::Error::msg),
b"lox!"=>rbx_binary::from_reader(input).map_err(anyhow::Error::msg), b"<roblox "=>rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()).map_err(anyhow::Error::msg),
b"lox "=>rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()).map_err(anyhow::Error::msg), _=>Err(anyhow::Error::msg("unsupported file type")),
other=>Err(anyhow::Error::msg(format!("Unknown Roblox file type {:?}",other))),
}
},
_=>Err(anyhow::Error::msg("unsupported file type")),
}
}else{
Err(anyhow::Error::msg("peek failed"))
} }
} }
@ -85,10 +71,11 @@ SurfaceAppearance.NormalMap
SurfaceAppearance.RoughnessMap SurfaceAppearance.RoughnessMap
SurfaceAppearance.TexturePack SurfaceAppearance.TexturePack
*/ */
fn accumulate_content_id(content_list:&mut HashSet<u64>,object:&Instance,property:&str){ fn accumulate_content_id(content_list:&mut HashSet<RobloxAssetId>,object:&Instance,property:&str){
if let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get(property){ 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>(){ let url:&str=content.as_ref();
content_list.insert(asset_id.0); if let Ok(asset_id)=url.parse(){
content_list.insert(asset_id);
}else{ }else{
println!("Content failed to parse into AssetID: {:?}",content); println!("Content failed to parse into AssetID: {:?}",content);
} }
@ -96,90 +83,70 @@ fn accumulate_content_id(content_list:&mut HashSet<u64>,object:&Instance,propert
println!("property={} does not exist for class={}",object.class.as_str(),property); println!("property={} does not exist for class={}",object.class.as_str(),property);
} }
} }
fn download_textures(paths:Vec<PathBuf>)->AResult<()>{ fn read_entire_file(path:impl AsRef<Path>)->Result<Cursor<Vec<u8>>,std::io::Error>{
println!("Reading files, this could take a hot minute..."); let mut file=std::fs::File::open(path)?;
let mut texture_list=HashSet::new(); let mut data=Vec::new();
for path in paths{ file.read_to_end(&mut data)?;
let file=match std::fs::File::open(path.as_path()){ Ok(Cursor::new(data))
Ok(file)=>file,
Err(e)=>{
println!("file error {e}");
continue;
}
};
let mut input=std::io::BufReader::new(file);
match load_dom(&mut input){
Ok(dom)=>{
for object in dom.into_raw().1.into_values(){
match object.class.as_str(){
"Beam"=>accumulate_content_id(&mut texture_list,&object,"Texture"),
"Decal"=>accumulate_content_id(&mut texture_list,&object,"Texture"),
"Texture"=>accumulate_content_id(&mut texture_list,&object,"Texture"),
"FileMesh"=>accumulate_content_id(&mut texture_list,&object,"TextureId"),
"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),
}
}
let texture_list_string=texture_list.into_iter().map(|id|id.to_string()).collect::<Vec<String>>();
println!("Texture list:{:?}",texture_list_string.join(" "));
std::fs::create_dir_all("textures/unprocessed")?;
let output=std::process::Command::new("asset-tool")
.args(["download","--cookie-literal","","--output-folder","textures/unprocessed/"])
.args(texture_list_string)
.spawn()?
.wait_with_output()?;
println!("Asset tool exit_success:{}",output.status.success());
Ok(())
} }
fn download_meshes(paths:Vec<PathBuf>)->AResult<()>{ #[derive(Default)]
println!("Reading files, this could take a hot minute..."); struct UniqueAssets{
let mut mesh_list=HashSet::new(); meshes:HashSet<RobloxAssetId>,
for path in paths{ unions:HashSet<RobloxAssetId>,
let file=match std::fs::File::open(path.as_path()){ textures:HashSet<RobloxAssetId>,
Ok(file)=>file, }
Err(e)=>{ impl UniqueAssets{
println!("file error {e}"); fn collect(&mut self,object:&Instance){
continue; match object.class.as_str(){
} "Beam"=>accumulate_content_id(&mut self.textures,object,"Texture"),
}; "Decal"=>accumulate_content_id(&mut self.textures,object,"Texture"),
let mut input=std::io::BufReader::new(file); "Texture"=>accumulate_content_id(&mut self.textures,object,"Texture"),
match load_dom(&mut input){ "FileMesh"=>accumulate_content_id(&mut self.textures,object,"TextureId"),
Ok(dom)=>{ "MeshPart"=>{
for object in dom.into_raw().1.into_values(){ accumulate_content_id(&mut self.textures,object,"TextureID");
match object.class.as_str(){ accumulate_content_id(&mut self.meshes,object,"MeshId");
"MeshPart"=>accumulate_content_id(&mut mesh_list,&object,"MeshId"),
"SpecialMesh"=>accumulate_content_id(&mut mesh_list,&object,"MeshId"),
_=>(),
}
}
}, },
Err(e)=>println!("error loading map {:?}: {:?}",path.file_name(),e), "SpecialMesh"=>accumulate_content_id(&mut self.meshes,object,"MeshId"),
"ParticleEmitter"=>accumulate_content_id(&mut self.textures,object,"Texture"),
"Sky"=>{
accumulate_content_id(&mut self.textures,object,"MoonTextureId");
accumulate_content_id(&mut self.textures,object,"SkyboxBk");
accumulate_content_id(&mut self.textures,object,"SkyboxDn");
accumulate_content_id(&mut self.textures,object,"SkyboxFt");
accumulate_content_id(&mut self.textures,object,"SkyboxLf");
accumulate_content_id(&mut self.textures,object,"SkyboxRt");
accumulate_content_id(&mut self.textures,object,"SkyboxUp");
accumulate_content_id(&mut self.textures,object,"SunTextureId");
},
"UnionOperation"=>accumulate_content_id(&mut self.unions,object,"AssetId"),
_=>(),
} }
} }
let mesh_list_string=mesh_list.into_iter().map(|id|id.to_string()).collect::<Vec<String>>(); }
println!("Mesh list:{:?}",mesh_list_string.join(" ")); fn unique_assets(path:&Path)->AResult<UniqueAssets>{
std::fs::create_dir_all("meshes/")?; // read entire file
let output=std::process::Command::new("asset-tool") let mut assets=UniqueAssets::default();
.args(["download","--cookie-literal","","--output-folder","meshes/"]) let data=read_entire_file(path)?;
.args(mesh_list_string) let dom=load_dom(data)?;
.spawn()? for object in dom.into_raw().1.into_values(){
.wait_with_output()?; assets.collect(&object);
println!("Asset tool exit_success:{}",output.status.success()); }
Ok(assets)
}
struct UniqueAssetsResult{
path:std::path::PathBuf,
result:AResult<UniqueAssets>,
}
fn do_thread(path:std::path::PathBuf,send:std::sync::mpsc::Sender<UniqueAssetsResult>){
std::thread::spawn(move ||{
let result=unique_assets(path.as_path());
send.send(UniqueAssetsResult{
path,
result,
}).unwrap();
});
}
fn download_assets(paths:Vec<PathBuf>)->AResult<()>{
Ok(()) Ok(())
} }