diff --git a/src/main.rs b/src/main.rs index cfe17e7..cc46761 100644 --- a/src/main.rs +++ b/src/main.rs @@ -168,6 +168,7 @@ async fn main()->AResult<()>{ input_folder:cli.input.unwrap(), output_file:cli.output.unwrap(), template:None, + style:None, }).await, Commands::Decompile=>decompile(DecompileConfig{ style:decompile_style.unwrap(), @@ -1275,11 +1276,12 @@ fn extract_script_overrides(mut source:String)->AResult{ Ok(ScriptWithOverrides{overrides,source:source.split_off(count)}) } -async fn discern_node(search_path:&std::path::PathBuf,search_name:&str,style:Option)->AResult>{ - let mut contents_folder=search_path.clone(); - contents_folder.push(search_name); +async fn discern_node(entry:&tokio::fs::DirEntry,style:Option)->AResult>{ + let contents_folder=entry.path(); + let file_name=entry.file_name(); //folder Ok(if let Ok(dir)=tokio::fs::read_dir(contents_folder.as_path()).await{ + let search_name=file_name.to_str().unwrap(); //scan inside the folder for an object to define the class of the folder let script_query=async {match style{ Some(DecompileStyle::Rox)=>QuerySingle::rox(&contents_folder,search_name).resolve().await, @@ -1345,6 +1347,12 @@ async fn discern_node(search_path:&std::path::PathBuf,search_name:&str,style:Opt None }) } + +async fn discern_file(entry:&tokio::fs::DirEntry,style:Option)->AResult>{ + todo!(); + Ok(None) +} + #[derive(Debug)] enum ScriptHint{ Script, @@ -1357,6 +1365,11 @@ struct FileHint{ hint:ScriptHint, } +enum PreparedData{ + Model(rbx_dom_weak::WeakDom), + Builder(rbx_dom_weak::InstanceBuilder), +} + enum CompileClass{ Folder, Script(String), @@ -1372,8 +1385,7 @@ struct CompileNode{ } enum CompileStackInstruction{ - Referent(rbx_dom_weak::types::Ref), - PushFolder(String), + TraverseReferent(rbx_dom_weak::types::Ref), PopFolder, } @@ -1381,6 +1393,14 @@ struct CompileConfig{ input_folder:std::path::PathBuf, output_file:std::path::PathBuf, template:Option, + style:Option, +} + +fn script_builder(class:&str,name:&str,source:String)->rbx_dom_weak::InstanceBuilder{ + let mut builder=rbx_dom_weak::InstanceBuilder::new(class); + builder.set_name(name); + builder.add_property("Source",rbx_dom_weak::types::Variant::String(source)); + builder } async fn compile(config:CompileConfig)->AResult<()>{ @@ -1400,28 +1420,81 @@ async fn compile(config:CompileConfig)->AResult<()>{ //add in scripts and models let mut folder=config.input_folder.clone(); folder.push("src"); - let mut stack:Vec=dom.root().children().into_iter().map(|&referent|CompileStackInstruction::Referent(referent)).collect(); + let mut stack:Vec=dom.root().children().into_iter().map(|&referent|CompileStackInstruction::TraverseReferent(referent)).collect(); while let Some(instruction)=stack.pop(){ match instruction{ - CompileStackInstruction::Referent(item_ref)=>{ - let item=dom.get_by_ref(item_ref).ok_or(anyhow::Error::msg("null child ref"))?; - //check if item exists in folder or subfolder of same name - todo!("this is totally unnecessary, - only the folder needs to exist to determine if traversal should continue"); - if let Some(obj)=discern_node(&folder,item.name.as_str(),None).await?{ - //cool - }else{ - //determine if this is ok - } - //push child objects onto dom - //push dom children objects onto stack + CompileStackInstruction::TraverseReferent(item_ref)=>{ + let sans={ + let item=dom.get_by_ref(item_ref).ok_or(anyhow::Error::msg("null child ref"))?; + sanitize(item.name.as_str()).to_string() + }; + folder.push(sans.as_str()); stack.push(CompileStackInstruction::PopFolder); - stack.extend(item.children().into_iter().map(|&referent|CompileStackInstruction::Referent(referent))); - stack.push(CompileStackInstruction::PushFolder(sanitize(item.name.as_str()).to_string())); + //check if a folder exists with item.name + if let Ok(mut dir)=tokio::fs::read_dir(folder.as_path()).await{ + let mut exist_names=std::collections::HashSet::new(); + { + let item=dom.get_by_ref(item_ref).ok_or(anyhow::Error::msg("null child ref"))?; + for &child_ref in item.children(){ + let child=dom.get_by_ref(child_ref).ok_or(anyhow::Error::msg("null child ref"))?; + let child_sans=sanitize(child.name.as_str()).to_string(); + exist_names.insert(child_sans); + } + } + //generate children from folder contents UNLESS! item already has a child of the same name + let mut join_set=tokio::task::JoinSet::new(); + //I wish I could make the join_next() loop begin processing immediately, + //but I don't know an ergonomic way to do that. + //this will probably be fine considering there won't be millions of files in the directories + while let Some(entry)=dir.next_entry().await?{ + //cull early even if supporting things with identical names is possible + if !exist_names.contains(entry.file_name().to_str().unwrap()){ + let style=config.style; + join_set.spawn(async move{ + //discern that bad boy + match tokio::join!(discern_node(&entry,style),discern_file(&entry,style)){ + (Ok(Some(compile_class)),Ok(None)) + |(Ok(None),Ok(Some(compile_class)))=>{ + //prepare data structure + match compile_class.class{ + CompileClass::Folder=>Ok(Some(PreparedData::Builder(rbx_dom_weak::InstanceBuilder::new("Folder").with_name(compile_class.name.as_str())))), + CompileClass::Script(source)=>Ok(Some(PreparedData::Builder(script_builder("Script",compile_class.name.as_str(),source)))), + CompileClass::LocalScript(source)=>Ok(Some(PreparedData::Builder(script_builder("LocalScript",compile_class.name.as_str(),source)))), + CompileClass::ModuleScript(source)=>Ok(Some(PreparedData::Builder(script_builder("ModuleScript",compile_class.name.as_str(),source)))), + CompileClass::Model(buf)=>Ok(Some(PreparedData::Model(rbx_xml::from_reader_default(std::io::Cursor::new(buf))?))), + } + }, + (Ok(Some(_)),Ok(Some(_)))=>panic!("File and folder have the same name!"), + (Ok(None),Ok(None))=>Ok(None), + (Err(e),_) + |(_,Err(e))=>Err(e), + } + }); + } + } + //this is only able to begin after dir iterator is exhausted + //push child objects onto dom + while let Some(goober)=join_set.join_next().await{ + match goober??{ + Some(PreparedData::Model(mut model_dom))=>model_dom.transfer(model_dom.root().children()[0],&mut dom,item_ref), + Some(PreparedData::Builder(script))=>{dom.insert(item_ref,script);}, + None=>print!("There was a None"), + } + } + //push dom children objects onto stack + let item=dom.get_by_ref(item_ref).ok_or(anyhow::Error::msg("null child ref"))?; + stack.extend(item.children().into_iter().map(|&referent|CompileStackInstruction::TraverseReferent(referent))); + } }, - CompileStackInstruction::PushFolder(component)=>folder.push(component), CompileStackInstruction::PopFolder=>assert!(folder.pop(),"pop folder bad"), } } + + let mut output_place=config.output_file.clone(); + if output_place.extension().is_none(){ + output_place.push("place.rbxl"); + } + let output=std::io::BufWriter::new(std::fs::File::open(output_place)?); + rbx_binary::to_writer(output,&dom,&[dom.root_ref()])?; Ok(()) }