Skip to content

📦 Node.js wrapper around Unity3D's BuildPipeline to create AssetBundles from any files

License

Notifications You must be signed in to change notification settings

mitmadness/AssetBundleCompiler

Repository files navigation

AssetBundleCompiler logo

AssetBundleCompiler

npm version license Travis Build npm total downloads

Node.js wrapper around Unity3D's BuildPipeline to create AssetBundles programmatically from any files, in order to simplify and automatize your workflow.

From the documentation:

AssetBundles are files which you can export from Unity to contain Assets of your choice, [that] can be loaded on demand by your application. This allows you to stream content, such as models, Textures, audio clips, or even entire Scenes [...].

👉 See also: @mitm/chuck, a fully-featured webservice that builds asset bundles.


Build automation with Unity's CLI and generating asset bundles gives headaches. If you are integrating asset bundle generation in a Node.js server or want a simple tool to do it, AssetBundleCompiler may satisfy you:

await bundle(...assets).targeting(WebGL).to('/path/to/asset.bundle');

📦 Installation & Usage

Requirements:

  • Node.js, version 7 preferred
  • ⚠️ An activated installation of Unity on the machine ⚠️

Install it via the npm registry:

yarn add @mitm/assetbundlecompiler

🔗 Simple, fluent API

import { BuildTargets, bundle } from '@mitm/assetbundlecompiler';

const { WebGL } = BuildTargets;

// bundle() is the entry function to the API.
// Pass a list of assets to bundle into the resulting asset bundle.
// Those assets could be anywhere on the filesystem.
// To pass an array of paths, use bundle(...paths) syntax.
await bundle('/abs/path/to/fbx', '/abs/path/to/texture', /* ... */)
    // .targeting() is mandatory and tells the library what platform your asset bundle targets.
    // You can either pass a predefined constant in BuildTargets, or a string,
    // matching the name of a member of the UnityEditor.BuildTarget enum.
    // @see https://docs.unity3d.com/ScriptReference/BuildTarget.html
    .targeting(WebGL)
    
    // Lets you install custom Editor scripts before asset bundle generation.
    // This is very useful, for example, to create an Asset Postprocessor to customize how
    // your resources are imported into the asset bundle, using AssetImporters for example.
    // @see https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html
    .includingEditorScripts('/abs/path/to/script.dll', '/abs/path/to/script.cs')
    
    // Lets you define build options. Those are always flags, and the key names represent
    // member names of the UnityEditor.BuildAssetBundleOptions enum.
    // @see https://docs.unity3d.com/ScriptReference/BuildAssetBundleOptions.html
    .withBuildOptions({ chunkBasedCompression: true, strictMode: true, /* etc */ })
    
    // This lets you define a simple logger to get simple text updates about the conversion.
    .withLogger(message => console.log(message))
    
    // This lets you define a logger for the real-time output of Unity (stdout+stderr).
    // Beware, it's very verbose :)
    .withUnityLogger(message => console.log(`Unity: ${message}`))
    
    // This is the "run" function and marks the termination of the fluent calls
    // by returning a Promise that resolves when the asset bundle generation ends.
    // Give it a path to the asset bundle name or a fs.WriteStream.
    .to('/abs/path/to/resources.assetbundle');

You can also retrieve the manifest Unity generates during the build - the manifest contains informations about the asset bundle:

// The promise gets resolved with the manifest as a plain JS object
const manifest = await bundle('...').to('...');

/* manifest = { 
    CRC: 2924050344,
    Assets: ['Assets/CopiedAssets/MyAsset.jpg'],
    ...etc...
} */

You can also dump the original manifest file (a YAML file) alongside the assetbundle:

const manifest = await bundle('...')
    // manifestFile can take a path or a fs.WriteStream too
    .to('/path/to/resources.assetbundle', { manifestFile: '/path/to/resources.assetbundle.manifest' });

💡 Notes

Error handling

What could possibly go wrong?

AssetBundleCompiler will catch abnormal Unity process termination and throw an error in that case (and performs a rapid cleanup). The error is an instance of UnityCrashError (exported on the main module) and its prototype looks like:

class UnityCrashError extends Error {
    public readonly message: string; // Exception message
    public readonly unityLog: string; // Unity Editor log (contains crash information)
}

The logs will also be dumped to you system temporary folder (ie. /tmp) in a file named unity_crash.abcompiler.log (the complete path will be reported in the error's message).

Please note that SIGINT and SIGTERM signals are also catched and the same cleanup is performed.

Changing Unity's executable path

By default, AssetBundleCompiler will try to find Unity's executable on the expected locations. The library will look at the following paths:

  • /opt/Unity/Editor/Unity – Debian / Ubuntu with the official .deb package
  • /Applications/Unity/Unity.app/Contents/MacOS/Unity – MacOS
  • C:\Program Files (x86)\Unity\Editor\Unity.exe – Windows, Unity x86
  • C:\Program Files\Unity\Editor\Unity.exe – Windows, Unity x64

If you have a custom installation of Unity on a "non-standard" path (ie. you have multiple versions installed), you can tell AssetBundleCompiler where to look:

import { setUnityPath } from '@mitm/assetbundlecompiler';

// given that you define the environment variable UNITY_EDITOR_PATH, to avoid hardcoded path:
setUnityPath(process.env.UNITY_EDITOR_PATH);

Unity activation

Unity is a proprietary software that requires to be activated with a valid account, even if that's not necessary for building asset bundles. This library does not handle activation, meaning that you must already have an activated version of Unity on the machine.

Building asset bundles, does not requires a paid account. You can log in with your free Personal license.

Activation via Unity's CLI is possible too (for automating installation for example) but is somewhat broken from times to times, and does not works with personal licenses. So, given you have a paid accound, you can do:

~$ /path/to/Unity -quit -batchmode -serial SB-XXXX-XXXX-XXXX-XXXX-XXXX -username 'JoeBloggs@example.com' -password 'MyPassw0rd'