forked from StrafesNET/asset-tool
DecompileStyle
This commit is contained in:
parent
2260d9a565
commit
10f1ac313c
129
src/main.rs
129
src/main.rs
@ -33,6 +33,8 @@ struct Cli{
|
||||
no_scripts:Option<bool>,
|
||||
#[arg(long)]
|
||||
no_template:Option<bool>,
|
||||
#[arg(long)]
|
||||
style:Option<String>,
|
||||
|
||||
//git options
|
||||
#[arg(long)]
|
||||
@ -61,6 +63,13 @@ enum Commands{
|
||||
DownloadAndDecompileHistoryIntoGit,
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy)]
|
||||
enum DecompileStyle{
|
||||
Rox,
|
||||
Rojo,
|
||||
RoxRojo,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct PathBufList{
|
||||
paths:Vec<std::path::PathBuf>
|
||||
@ -108,6 +117,21 @@ async fn main()->AResult<()>{
|
||||
None=>None,
|
||||
};
|
||||
|
||||
let decompile_style=match cli.style.as_deref(){
|
||||
Some("rox")
|
||||
|Some("Rox")=>Some(DecompileStyle::Rox),
|
||||
Some("rojo")
|
||||
|Some("Rojo")=>Some(DecompileStyle::Rojo),
|
||||
Some("rox-rojo")
|
||||
|Some("rojo-rox")
|
||||
|Some("roxrojo")
|
||||
|Some("rojorox")
|
||||
|Some("RoxRojo")
|
||||
|Some("RojoRox")=>Some(DecompileStyle::RoxRojo),
|
||||
None=>None,
|
||||
_=>return Err(anyhow::Error::msg("Invalid style")),
|
||||
};
|
||||
|
||||
match cli.command{
|
||||
Commands::DownloadHistory=>download_history(DownloadHistoryConfig{
|
||||
output_folder:cli.output.unwrap(),
|
||||
@ -118,6 +142,7 @@ async fn main()->AResult<()>{
|
||||
Commands::Upload=>upload_list(cookie.unwrap(),cli.group,vec![(cli.asset_id.unwrap(),cli.output.unwrap())]).await,
|
||||
Commands::Compile=>compile(cli.input.unwrap(),cli.output.unwrap()),
|
||||
Commands::Decompile=>decompile(DecompileConfig{
|
||||
style:decompile_style.unwrap(),
|
||||
input_file:cli.input.unwrap(),
|
||||
output_folder:cli.output.unwrap(),
|
||||
write_template:!cli.no_template.unwrap_or(false),
|
||||
@ -129,6 +154,7 @@ async fn main()->AResult<()>{
|
||||
git_committer_email:cli.git_committer_email.unwrap(),
|
||||
input_folder:cli.input.unwrap(),
|
||||
output_folder:cli.output.unwrap(),
|
||||
style:decompile_style.unwrap(),
|
||||
write_template:!cli.no_template.unwrap_or(false),
|
||||
write_models:!cli.no_models.unwrap_or(false),
|
||||
write_scripts:!cli.no_scripts.unwrap_or(false),
|
||||
@ -139,6 +165,7 @@ async fn main()->AResult<()>{
|
||||
cookie:cookie.unwrap(),
|
||||
asset_id:cli.asset_id.unwrap(),
|
||||
output_folder:cli.output.unwrap(),
|
||||
style:decompile_style.unwrap(),
|
||||
write_template:!cli.no_template.unwrap_or(false),
|
||||
write_models:!cli.no_models.unwrap_or(false),
|
||||
write_scripts:!cli.no_scripts.unwrap_or(false),
|
||||
@ -427,15 +454,26 @@ enum WriteStackInstruction<'a>{
|
||||
Destroy(Ref),
|
||||
}
|
||||
|
||||
#[derive(Default,serde::Deserialize,serde::Serialize)]
|
||||
#[allow(nonstandard_style,dead_code)]
|
||||
#[derive(Default)]
|
||||
struct PropertiesOverride{
|
||||
//Name:Option<String>,
|
||||
ClassName:Option<String>,
|
||||
name:Option<String>,
|
||||
class_name:Option<String>,
|
||||
}
|
||||
impl PropertiesOverride{
|
||||
fn is_some(&self)->bool{
|
||||
self.ClassName.is_some()
|
||||
self.name.is_some()
|
||||
||self.class_name.is_some()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for PropertiesOverride{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
if let Some(name)=self.name.as_deref(){
|
||||
writeln!(f,"--! Properties.Name=\"{}\"",name)?;
|
||||
}
|
||||
if let Some(class_name)=self.class_name.as_deref(){
|
||||
writeln!(f,"--! Properties.ClassName=\"{}\"",class_name)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -443,7 +481,7 @@ fn sanitize<'a>(s:&'a str)->std::borrow::Cow<'a,str>{
|
||||
lazy_regex::regex!(r"[^a-zA-Z0-9._-]").replace_all(s,"_")
|
||||
}
|
||||
|
||||
fn write_item(dom:&rbx_dom_weak::WeakDom,mut file:std::path::PathBuf,node:&TreeNode,node_name_override:String,write_models:bool,write_scripts:bool)->AResult<()>{
|
||||
fn write_item(dom:&rbx_dom_weak::WeakDom,mut file:std::path::PathBuf,node:&TreeNode,node_name_override:String,mut properties:PropertiesOverride,style:DecompileStyle,write_models:bool,write_scripts:bool)->AResult<()>{
|
||||
file.push(sanitize(node_name_override.as_str()).as_ref());
|
||||
match node.class{
|
||||
Class::Folder=>(),
|
||||
@ -451,11 +489,40 @@ fn write_item(dom:&rbx_dom_weak::WeakDom,mut file:std::path::PathBuf,node:&TreeN
|
||||
if !write_scripts{
|
||||
return Ok(())
|
||||
}
|
||||
assert!(file.set_extension("lua"),"could not set extension");
|
||||
|
||||
//set extension
|
||||
match style{
|
||||
DecompileStyle::Rox=>assert!(file.set_extension("lua"),"could not set extension"),
|
||||
DecompileStyle::RoxRojo|DecompileStyle::Rojo=>{
|
||||
match properties.class_name.as_deref(){
|
||||
Some("LocalScript")=>{
|
||||
file.set_extension("client.lua");
|
||||
properties.class_name=None;
|
||||
},
|
||||
Some("Script")=>{
|
||||
file.set_extension("server.lua");
|
||||
properties.class_name=None;
|
||||
},
|
||||
// Some("ModuleScript")=>{
|
||||
// file.set_extension("module");
|
||||
// properties.class_name=None;
|
||||
// },
|
||||
None=>assert!(file.set_extension("lua"),"could not set extension"),
|
||||
Some(other)=>return Err(anyhow::Error::msg(format!("Attempt to write a {} as a script",other))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(item)=dom.get_by_ref(node.referent){
|
||||
//TODO: delete disabled scripts
|
||||
if let Some(rbx_dom_weak::types::Variant::String(source))=item.properties.get("Source"){
|
||||
if properties.is_some(){
|
||||
//rox style
|
||||
let source=properties.to_string()+source.as_str();
|
||||
std::fs::write(file,source)?;
|
||||
}else{
|
||||
std::fs::write(file,source)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -574,6 +641,7 @@ fn generate_decompiled_context<R:Read>(input:R)->AResult<DecompiledContext>{
|
||||
}
|
||||
|
||||
struct WriteConfig{
|
||||
style:DecompileStyle,
|
||||
output_folder:std::path::PathBuf,
|
||||
write_template:bool,
|
||||
write_models:bool,
|
||||
@ -593,44 +661,41 @@ async fn write_files(config:WriteConfig,mut context:DecompiledContext)->AResult<
|
||||
WriteStackInstruction::PopFolder=>assert!(folder.pop(),"weirdness"),
|
||||
WriteStackInstruction::Destroy(referent)=>destroy_queue.push(referent),
|
||||
WriteStackInstruction::Node(node,name_count)=>{
|
||||
//properties.json to override class or other simple properties
|
||||
//track properties that must be overriden to compile folder structure back into a place file
|
||||
let mut properties=PropertiesOverride::default();
|
||||
let has_children=node.children.len()!=0;
|
||||
match node.class{
|
||||
Class::Folder=>(),
|
||||
Class::ModuleScript=>{
|
||||
//.lua files are ModuleScript by default
|
||||
if has_children{
|
||||
properties.ClassName=Some("ModuleScript".to_string())
|
||||
}
|
||||
},
|
||||
Class::LocalScript=>properties.ClassName=Some("LocalScript".to_string()),
|
||||
Class::Script=>properties.ClassName=Some("Script".to_string()),
|
||||
Class::ModuleScript=>(),//.lua files are ModuleScript by default
|
||||
Class::LocalScript=>properties.class_name=Some("LocalScript".to_string()),
|
||||
Class::Script=>properties.class_name=Some("Script".to_string()),
|
||||
Class::Model=>(),
|
||||
}
|
||||
let name_override=if 0<name_count{
|
||||
properties.name=Some(node.name.clone());
|
||||
format!("{}_{}",node.name,name_count)
|
||||
}else{
|
||||
node.name.clone()
|
||||
};
|
||||
if has_children||properties.is_some(){
|
||||
|
||||
if has_children{
|
||||
//push temp subfolder
|
||||
let mut subfolder=folder.clone();
|
||||
subfolder.push(sanitize(name_override.as_str()).as_ref());
|
||||
//make folder
|
||||
tokio::fs::create_dir(subfolder.clone()).await?;
|
||||
//write properties
|
||||
if properties.is_some(){
|
||||
let mut file=subfolder.clone();
|
||||
file.push("properties");
|
||||
assert!(file.set_extension("json"),"could not set extension");
|
||||
tokio::fs::write(file,serde_json::to_string(&properties)?).await?;
|
||||
}
|
||||
|
||||
let name_final=match config.style{
|
||||
DecompileStyle::Rox
|
||||
|DecompileStyle::RoxRojo=>name_override.clone(),
|
||||
DecompileStyle::Rojo=>"init".to_owned(),
|
||||
};
|
||||
|
||||
//write item in subfolder
|
||||
write_queue.push((subfolder,node,name_override.clone()));
|
||||
write_queue.push((subfolder,node,name_final,properties,config.style));
|
||||
}else{
|
||||
//write item
|
||||
write_queue.push((folder.clone(),node,name_override.clone()));
|
||||
write_queue.push((folder.clone(),node,name_override.clone(),properties,config.style));
|
||||
}
|
||||
//queue item to be deleted from dom after child objects are handled (stack is popped from the back)
|
||||
match node.class{
|
||||
@ -657,8 +722,8 @@ async fn write_files(config:WriteConfig,mut context:DecompiledContext)->AResult<
|
||||
let dom=&context.dom;
|
||||
let write_models=config.write_models;
|
||||
let write_scripts=config.write_scripts;
|
||||
let results:Vec<AResult<()>>=rayon::iter::ParallelIterator::collect(rayon::iter::ParallelIterator::map(rayon::iter::IntoParallelIterator::into_par_iter(write_queue),|(write_path,node,node_name_override)|{
|
||||
write_item(&dom,write_path,node,node_name_override,write_models,write_scripts)
|
||||
let results:Vec<AResult<()>>=rayon::iter::ParallelIterator::collect(rayon::iter::ParallelIterator::map(rayon::iter::IntoParallelIterator::into_par_iter(write_queue),|(write_path,node,node_name_override,properties,style)|{
|
||||
write_item(&dom,write_path,node,node_name_override,properties,style,write_models,write_scripts)
|
||||
}));
|
||||
for result in results{
|
||||
result?;
|
||||
@ -683,6 +748,7 @@ async fn write_files(config:WriteConfig,mut context:DecompiledContext)->AResult<
|
||||
}
|
||||
|
||||
struct DecompileConfig{
|
||||
style:DecompileStyle,
|
||||
input_file:std::path::PathBuf,
|
||||
output_folder:std::path::PathBuf,
|
||||
write_template:bool,
|
||||
@ -703,6 +769,7 @@ async fn decompile(config:DecompileConfig)->AResult<()>{
|
||||
//generate folders, models, and scripts
|
||||
//delete models and scripts from dom
|
||||
write_files(WriteConfig{
|
||||
style:config.style,
|
||||
output_folder:config.output_folder,
|
||||
write_template:config.write_template,
|
||||
write_models:config.write_models,
|
||||
@ -716,6 +783,7 @@ struct WriteCommitConfig{
|
||||
git_committer_name:String,
|
||||
git_committer_email:String,
|
||||
output_folder:std::path::PathBuf,
|
||||
style:DecompileStyle,
|
||||
write_template:bool,
|
||||
write_models:bool,
|
||||
write_scripts:bool,
|
||||
@ -745,6 +813,7 @@ async fn write_commit(config:WriteCommitConfig,b:Result<AResult<(AssetVersion,De
|
||||
|
||||
//write files
|
||||
write_files(WriteConfig{
|
||||
style:config.style,
|
||||
output_folder:config.output_folder.clone(),
|
||||
write_template:config.write_template,
|
||||
write_models:config.write_models,
|
||||
@ -804,6 +873,7 @@ struct DecompileHistoryConfig{
|
||||
git_committer_name:String,
|
||||
git_committer_email:String,
|
||||
input_folder:std::path::PathBuf,
|
||||
style:DecompileStyle,
|
||||
output_folder:std::path::PathBuf,
|
||||
write_template:bool,
|
||||
write_models:bool,
|
||||
@ -834,6 +904,7 @@ async fn decompile_history_into_git(config:DecompileHistoryConfig)->AResult<()>{
|
||||
match write_commit(WriteCommitConfig{
|
||||
git_committer_name:config.git_committer_name.clone(),
|
||||
git_committer_email:config.git_committer_email.clone(),
|
||||
style:config.style,
|
||||
output_folder:config.output_folder.clone(),
|
||||
write_template:config.write_template,
|
||||
write_models:config.write_models,
|
||||
@ -851,6 +922,7 @@ struct DownloadAndDecompileHistoryConfig{
|
||||
asset_id:AssetID,
|
||||
git_committer_name:String,
|
||||
git_committer_email:String,
|
||||
style:DecompileStyle,
|
||||
output_folder:std::path::PathBuf,
|
||||
write_template:bool,
|
||||
write_models:bool,
|
||||
@ -884,6 +956,7 @@ async fn download_and_decompile_history_into_git(config:DownloadAndDecompileHist
|
||||
.buffered(CONCURRENT_DECODE)
|
||||
.for_each(|join_handle_result|async{
|
||||
match write_commit(WriteCommitConfig{
|
||||
style:config.style,
|
||||
git_committer_name:config.git_committer_name.clone(),
|
||||
git_committer_email:config.git_committer_email.clone(),
|
||||
output_folder:config.output_folder.clone(),
|
||||
|
Loading…
Reference in New Issue
Block a user