Skip to content

Getting Started: Bundle file reading

nesrak1 edited this page Sep 23, 2023 · 7 revisions

This is a simple program to read every Texture2D in a bundle file and print its name and dimensions. Make sure to read Getting Started: Assets file reading first.

using AssetsTools.NET;
using AssetsTools.NET.Extra;

void LoadBundleFile(string filePath)
{
    var manager = new AssetsManager();

    var bunInst = manager.LoadBundleFile(args[0], true);
    var afileInst = manager.LoadAssetsFileFromBundle(bunInst, 0, false);
    var afile = afileInst.file;

    foreach (var texInfo in afile.GetAssetsOfType(AssetClassID.Texture2D))
    {
        var texBase = manager.GetBaseField(afileInst, texInfo);
        var name = texBase["m_Name"].AsString;
        var width = texBase["m_Width"].AsInt;
        var height = texBase["m_Height"].AsInt;
        Console.WriteLine($"Texture {name} is sized {width}x{height}");
    }
}

if (args.Length < 1)
{
    Console.WriteLine("need a file argument");
    return;
}

LoadBundleFile(args[0]);

Let's go over each part of the program.

var manager = new AssetsManager();

Like last time, we create an AssetsManager to manage assets/bundles. This time, however, we don't load the class package. We don't need it since most bundles have this information embedded in the "type tree".

var bunInst = manager.LoadBundleFile(args[0], true);
var afileInst = manager.LoadAssetsFileFromBundle(bunInst, 0, false);
var afile = afileInst.file;

First, we tell the manager to load the bundle file with the "decompress" flag set to true. This means AT will decompress LZMA bundles fully to memory and reopen it. You may want to set this to false and decompress manually if the bundle is > 1GB. For LZ4 bundles, they will be decompressed in pieces as you read it. If you set the decompress flag to false, you can check if the data is compressed or not by checking bunInst.file.DataIsCompressed.

Next, we load the first assets file (index 0) in the bundle. You can use bunInst.file.GetAllFileNames() to list all files if you want.

foreach (var texInfo in afile.GetAssetsOfType(AssetClassID.Texture2D))
{
    var texBase = manager.GetBaseField(afileInst, texInfo);
    var name = texBase["m_Name"].AsString;
    var width = texBase["m_Width"].AsInt;
    var height = texBase["m_Height"].AsInt;
    Console.WriteLine($"Texture {name} is sized {width}x{height}");
}

Finally, we loop over all Texture2D infos. For each one, we deserialize the asset to get the base field, then we read and print the name, width, and height.

Do I need to load the class package?

Most bundles have a type tree, so loading the class database isn't necessary for reading. However, if the game uses DisableWriteTypeTree, you will need to load the class package. You can check this by opening any of the assets files in your bundle and checking if afile.Metadata.TypeTreeEnabled is true. If it is, you're all set. Otherwise, you need to read the class package.

My bundle is very large. How do I decompress to file?

var bunInst = manager.LoadBundleFile(args[0], false);
var bunStream = File.Open("somepath.unity3d", FileMode.Create);
bunInst.file = BundleHelper.UnpackBundleToStream(bunInst.file, bunStream);