Development on this repository has concluded. Due to limited time and shifting priorities, I am no longer maintaining this crate.
To ensure the project continues to thrive, full maintenance and ownership—including the crates.io package—have been transferred. Please redirect all future updates, issues, and pull requests to the active repository:
➡️ jakobhellermann/RustyAssetBundleEXtractor
A work-in-progress extractor and patcher for Unity Engine asset files. Currently it can do about nothing, so please check back later.
This projects uses following dependencies:
-
Compression & Decompression:
-
Other:
use std::{
fs::{DirBuilder, File},
io::{Seek, Write},
path::Path,
};
use rabex::files::{BundleFile, SerializedFile};
use rabex::config::ExtractionConfig;
let mut reader = File::open(fp).unwrap();
let export_dir = Path::new("dump");
// parse the bundle file
let config = ExtractionConfig::new();
let mut bundle = BundleFile::from_reader(&mut reader, &config).unwrap();
// iterate over the files in the bundle
for directory in &bundle.m_DirectoryInfo {
// generate export dir for cab
let export_cab_dir = export_dir.join(&directory.path);
// seek to the start of the file in the bundle
bundle
.m_BlockReader
.seek(std::io::SeekFrom::Start(directory.offset as u64))
.unwrap();
// try to parse the file as a SerializedFile
match SerializedFile::from_reader(&mut bundle.m_BlockReader, &config) {
Ok(serialized) => {
// iterate over objects
for object in &serialized.m_Objects {
// get a helper object to parse the object
let mut handler =
serialized.get_object_handler(object, &mut bundle.m_BlockReader);
// try to get the name
let name = match handler.peak_name() {
Ok(name) => format!("{}_{}", object.m_PathID, name),
Err(_) => format!("{}", object.m_PathID),
};
// ensure that the parent directory exists
let dst_path = export_cab_dir.join(name);
DirBuilder::new()
.recursive(true)
.create(dst_path.parent().unwrap())
.unwrap_or_else(|_| panic!("Failed to create {:?}", dst_path.parent()));
// parse the object as json
let json = handler.parse_as_json().unwrap();
// println!("{:?}", json);
File::create(format!("{}.json", dst_path.to_string_lossy()))
.unwrap()
.write_all(json.to_string().as_bytes())
.unwrap();
// parse the object as yaml
let yaml = handler.parse_as_yaml().unwrap().unwrap();
// println!("{:?}", yaml);
File::create(format!("{}.yaml", dst_path.to_string_lossy()))
.unwrap()
.write_all(serde_yaml::to_string(&yaml).unwrap().as_bytes())
.unwrap();
// parse the object as msgpack
let msgpack = handler.parse_as_msgpack().unwrap();
File::create(format!("{}.msgpack", dst_path.to_string_lossy()))
.unwrap()
.write_all(&msgpack)
.unwrap();
// serialize as actual class
// note: a small part of the object classes isn't implemented yet
if object.m_ClassID == rabex::objects::map::AssetBundle {
let ab = handler
.parse::<rabex::objects::classes::AssetBundle>()
.unwrap();
println!("{:?}", ab);
}
}
}
Err(e) => {
// TODO - try to filter out resource files
println!(
"Failed to parse {} as SerializedFile.",
&directory.path.to_string()
);
}
}
}let mut reader = File::open(fp).unwrap();
let config = ExtractionConfig {
unitycn_key: Some("Decryption Key".as_bytes().try_into().unwrap()),
fallback_unity_version: "2020.3.0f1".to_owned(),
};
let bundle = crate::files::BundleFile::from_reader(&mut reader, &config).unwrap();-
Parsers:
- SerializedFile
- BundleFile
- WebFile
-
Object Classes:
- Generator
- Parser
- Writer
- Export Functions
-
Tests:
- Normal Tests
- Artificing Test Files
- 100% Coverage
-
Other:
- feature config
TODO:
- Docs
- GitHub Issues and Discussion
- Discord server
See CONTRIBUTING.md.
RustyAssetBundleEXtractor is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0).
See LICENSE-APACHE, LICENSE-MIT, and COPYRIGHT for details.