rabex 0.1.1

Tools for parsing and writing unity files, bundles and typetrees
Documentation

RustyAssetBundleEXtractor (rabex)

Latest Version Docs License_MIT License_APACHE

A crate for working with Unity Engine asset files. It supports reading and writing bundle files and serialized files, as well as reading typetrees with serde integration.

Maintained fork of UniversalGameExtraction/RustyAssetBundleEXtractor, and source of the rabex crate on crates.io.

Features

  • parsing and writing of unity serializedfiles (level0, globalgamemanagers, resources.assets)
  • parsing and writing of unity bundle files (data.unity3d, assetbundle.bundle, e.g. used by addressables)
  • serde [de]serialization of objects using typetrees
  • an embedded listing of builtin typetrees using https://github.com/AssetRipper/Tpk

Examples

Parsing an AssetBundle and dumping its objects

use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, Cursor};
use std::path::Path;

use anyhow::Result;
use rabex::files::SerializedFile;
use rabex::files::bundlefile::{BundleFileReader, ExtractionConfig};
use rabex::objects::{ClassId, PPtr};
use rabex::tpk::TpkTypeTreeBlob;
use rabex::typetree::typetree_cache::sync::TypeTreeCache;
use serde_derive::Deserialize;

fn main() -> Result<()> {
    let tpk = TypeTreeCache::new(TpkTypeTreeBlob::embedded());

    let path = std::env::args()
        .nth(1)
        .ok_or_else(|| anyhow::anyhow!("Expected path to unity bundle argument"))?;
    let config = ExtractionConfig::default().assume_recent_unity();

    let mut reader = BufReader::new(File::open(path)?);
    let mut bundle = BundleFileReader::from_reader(&mut reader, &config)?;

    let export_dir = Path::new("out");
    std::fs::create_dir_all(&export_dir)?;

    while let Some(mut file) = bundle.next_serialized() {
        let data = file.read()?;
        let reader = &mut Cursor::new(data);

        let serialized = SerializedFile::from_reader(reader)?;

        println!(
            "Contains typetree information: {}",
            serialized.m_EnableTypeTree
        );

        for object in serialized.objects() {
            println!("{:?} at {}", object.m_ClassID, object.m_PathID);

            let data = serialized.read::<serde_json::Value>(object, &tpk, reader)?;
            let name = data["m_Name"].as_str().unwrap();

            let object_path = export_dir.join(name);

            std::fs::write(object_path, serde_json::to_string_pretty(&data)?)?;

            // Objects can be deserialized into any `serde` type
            if object.m_ClassID == ClassId::AssetBundle {
                let asset_bundle = serialized.read::<AssetBundle>(object, &tpk, reader)?;
                println!("Asset Bundle: {:#?}", asset_bundle);
            }
        }
    }

    Ok(())
}

#[derive(Debug, Deserialize, Default)]
#[allow(non_snake_case)]
pub struct AssetBundle {
    pub m_Name: String,
    pub m_PreloadTable: Vec<PPtr>,
    pub m_AssetBundleName: String,
    pub m_IsStreamedSceneAssetBundle: bool,
    pub m_SceneHashes: HashMap<String, String>,
    // ...
}

Creating an assetbundle from scratch using BundleFileBuilder and SerializedFileBuilder

examples/create_assetbundle.rs

Related Projects

  • rabex-env: Higher-level wrapper around this crate, with support for resolving PPtr dependencies through different files, centered around the Environment abstraction.
  • unity-scene-repacker: Command line tool for repacking unity scenes and asset bundles into distilled versions suitable for loading certain objects in mods
  • steam-multiversion-viewer: [wip] Visual exploration tool for steam game versions, with support for reading and structurally diffing unity game files.

License

RustyAssetBundleEXtractor is licensed under either of Apache License, Version 2.0 or MIT license at your option.