wip download_assets (pre-tokio)
This commit is contained in:
parent
349cd9c233
commit
a5079f21d7
185
src/roblox.rs
185
src/roblox.rs
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user