Compare commits
5 Commits
81e4a201bd
...
479dd37f53
Author | SHA1 | Date | |
---|---|---|---|
479dd37f53 | |||
34b6a869f0 | |||
19a455ee5e | |||
9904b7a044 | |||
6efa811eb6 |
47
Cargo.lock
generated
47
Cargo.lock
generated
@ -2,6 +2,15 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.5.0"
|
||||
@ -264,14 +273,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "map-tool"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"rbx_binary",
|
||||
"rbx_dom_weak",
|
||||
"rbx_reflection_database",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.16"
|
||||
@ -423,6 +439,35 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
||||
|
||||
[[package]]
|
||||
name = "rmp"
|
||||
version = "0.8.12"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "map-tool"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
@ -10,6 +10,7 @@ clap = { version = "4.4.2", features = ["derive"] }
|
||||
rbx_binary = "0.7.1"
|
||||
rbx_dom_weak = "2.5.0"
|
||||
rbx_reflection_database = "0.2.7"
|
||||
regex = "1.9.5"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
137
src/main.rs
137
src/main.rs
@ -19,16 +19,17 @@ struct Cli {
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Download(MapList),
|
||||
DownloadTextures(PathBufList),
|
||||
Upload,
|
||||
Scan,
|
||||
Extract(Map),
|
||||
Extract(PathBufList),
|
||||
Replace,
|
||||
Interactive,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct Map {
|
||||
id:u64,
|
||||
struct PathBufList {
|
||||
paths:Vec<std::path::PathBuf>
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
@ -48,13 +49,13 @@ fn class_is_a(class: &str, superclass: &str) -> bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
fn recursive_collect_scripts(scripts: &mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance){
|
||||
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(), "LuaSourceContainer") {
|
||||
scripts.push(c.referent());//copy ref
|
||||
if class_is_a(c.class.as_str(), superclass) {
|
||||
objects.push(c.referent());//copy ref
|
||||
}
|
||||
recursive_collect_scripts(scripts,dom,c);
|
||||
recursive_collect_superclass(objects,dom,c,superclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,9 +90,17 @@ fn get_full_name(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance) ->
|
||||
|
||||
fn get_script_refs(dom:&rbx_dom_weak::WeakDom) -> Vec<rbx_dom_weak::types::Ref>{
|
||||
let mut scripts = std::vec::Vec::new();
|
||||
recursive_collect_scripts(&mut scripts, dom, dom.root());
|
||||
recursive_collect_superclass(&mut scripts, dom, dom.root(),"LuaSourceContainer");
|
||||
scripts
|
||||
}
|
||||
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_id() -> BoxResult<u32>{
|
||||
match std::fs::read_to_string("id"){
|
||||
@ -189,8 +198,95 @@ fn download(map_list: Vec<u64>) -> BoxResult<()>{
|
||||
.spawn()
|
||||
}).collect();
|
||||
//naively wait for all because idk how to make an async progress bar lmao
|
||||
for mut child in processes_result?{
|
||||
child.wait()?;
|
||||
for child in processes_result?{
|
||||
let output=child.wait_with_output()?;
|
||||
println!("map exit_success:{}",output.status.success());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct RobloxAssetId(u64);
|
||||
struct RobloxAssetIdParseErr;
|
||||
impl std::str::FromStr for RobloxAssetId {
|
||||
type Err=RobloxAssetIdParseErr;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err>{
|
||||
let regman=regex::Regex::new(r"(\d+)$").unwrap();
|
||||
if let Some(captures) = regman.captures(s) {
|
||||
if captures.len()==2{//captures[0] is all captures concatenated, and then each individual capture
|
||||
if let Ok(id) = captures[0].parse::<u64>() {
|
||||
return Ok(Self(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(RobloxAssetIdParseErr)
|
||||
}
|
||||
}
|
||||
/* The ones I'm interested in:
|
||||
Beam.Texture
|
||||
Decal.Texture
|
||||
FileMesh.MeshId
|
||||
FileMesh.TextureId
|
||||
MaterialVariant.ColorMap
|
||||
MaterialVariant.MetalnessMap
|
||||
MaterialVariant.NormalMap
|
||||
MaterialVariant.RoughnessMap
|
||||
MeshPart.MeshId
|
||||
MeshPart.TextureID
|
||||
ParticleEmitter.Texture
|
||||
Sky.MoonTextureId
|
||||
Sky.SkyboxBk
|
||||
Sky.SkyboxDn
|
||||
Sky.SkyboxFt
|
||||
Sky.SkyboxLf
|
||||
Sky.SkyboxRt
|
||||
Sky.SkyboxUp
|
||||
Sky.SunTextureId
|
||||
SurfaceAppearance.ColorMap
|
||||
SurfaceAppearance.MetalnessMap
|
||||
SurfaceAppearance.NormalMap
|
||||
SurfaceAppearance.RoughnessMap
|
||||
SurfaceAppearance.TexturePack
|
||||
*/
|
||||
fn download_textures(paths: Vec<std::path::PathBuf>) -> BoxResult<()>{
|
||||
println!("download_textures paths:{:?}",paths);
|
||||
let header=format!("Cookie: .ROBLOSECURITY={}",std::env::var("RBXCOOKIE")?);
|
||||
let shared_args=&[
|
||||
"-q",
|
||||
"--header",
|
||||
header.as_str(),
|
||||
"-O",
|
||||
];
|
||||
let mut texture_list=std::collections::HashSet::new();
|
||||
for path in paths {
|
||||
let input = std::io::BufReader::new(std::fs::File::open(path)?);
|
||||
|
||||
let dom = rbx_binary::from_reader(input)?;
|
||||
|
||||
let object_refs = get_texture_refs(&dom);
|
||||
|
||||
for &object_ref in object_refs.iter() {
|
||||
if let Some(object)=dom.get_by_ref(object_ref){
|
||||
if let Some(rbx_dom_weak::types::Variant::Content(content)) = object.properties.get("Texture") {
|
||||
println!("Texture content:{:?}",content);
|
||||
if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){
|
||||
texture_list.insert(asset_id.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Texture list:{:?}",texture_list);
|
||||
let processes_result:Result<Vec<_>, _>=texture_list.iter().map(|asset_id|{
|
||||
std::process::Command::new("wget")
|
||||
.args(shared_args)
|
||||
.arg(format!("textures/{}",asset_id))
|
||||
.arg(format!("https://assetdelivery.roblox.com/v1/asset/?ID={}",asset_id))
|
||||
.spawn()
|
||||
}).collect();
|
||||
//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(())
|
||||
}
|
||||
@ -259,19 +355,15 @@ fn scan() -> BoxResult<()>{
|
||||
std::fs::write("id",id.to_string())?;
|
||||
Ok(())
|
||||
}
|
||||
fn extract(file_id:u64) -> BoxResult<()>{
|
||||
|
||||
fn extract(paths: Vec<std::path::PathBuf>) -> BoxResult<()>{
|
||||
let mut id = 0;
|
||||
//Construct allowed scripts
|
||||
let mut script_set = std::collections::HashSet::<String>::new();
|
||||
|
||||
let file_id_string=file_id.to_string();
|
||||
|
||||
for entry in std::fs::read_dir("maps/unprocessed")? {
|
||||
let file_thing=entry?;
|
||||
if file_thing.file_name().to_str().unwrap().find(&file_id_string).is_none(){
|
||||
continue;
|
||||
}
|
||||
let input = std::io::BufReader::new(std::fs::File::open(file_thing.path())?);
|
||||
for path in paths {
|
||||
let file_name=path.file_name();
|
||||
let input = std::io::BufReader::new(std::fs::File::open(&path)?);
|
||||
|
||||
let dom = rbx_binary::from_reader(input)?;
|
||||
|
||||
@ -285,11 +377,11 @@ fn extract(file_id:u64) -> BoxResult<()>{
|
||||
continue;
|
||||
}else{
|
||||
script_set.insert(s.clone());
|
||||
std::fs::write(format!("scripts/extracted/{:?}_{}_{}.lua",file_thing.file_name(),id,script.name),s)?;
|
||||
std::fs::write(format!("scripts/extracted/{:?}_{}_{}.lua",file_name,id,script.name),s)?;
|
||||
id+=1;
|
||||
}
|
||||
}else{
|
||||
panic!("FATAL: failed to get source for {:?}",file_thing.file_name());
|
||||
panic!("FATAL: failed to get source for {:?}",file_name);
|
||||
}
|
||||
}else{
|
||||
panic!("FATAL: failed to get_by_ref {:?}",script_ref);
|
||||
@ -654,10 +746,11 @@ fn main() -> BoxResult<()> {
|
||||
let cli = Cli::parse();
|
||||
match cli.command {
|
||||
Commands::Download(map_list)=>download(map_list.maps),
|
||||
Commands::DownloadTextures(pathlist)=>download_textures(pathlist.paths),
|
||||
Commands::Upload=>upload(),
|
||||
Commands::Scan=>scan(),
|
||||
Commands::Replace=>replace(),
|
||||
Commands::Interactive=>interactive(),
|
||||
Commands::Extract(map)=>extract(map.id),
|
||||
Commands::Extract(pathlist)=>extract(pathlist.paths),
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user