New AssetBundle build system in Unity 5.0

[EDIT]

This post is now OBSOLETE!
Please visit this page for up-to-date details.
__*http://unity3d.com/learn/tutorials/topics/scripting/assetbundles-and-assetbundle-manager?playlist=17117*__
To discuss this topic, please use this thread:
__*The AssetBundle Manager Tutorial Q&A - Learn Content & Certification - Unity Discussions

[/EDIT]

In Unity 5.0, we have a new AssetBundle build system which is much more easier to use than the old one.

Basic Introduction

In the new AssetBundle build system, we provide:

  • Simple UI to mark the assets into an AssetBundles, and keep the assets to AssetBundles mapping in the asset database.

  • You can find the UI at the bottom of the asset preview panel. It’s very simple, just try to use it.

  • The AssetBundle name will be stored in the meta file.

  • Also provide search filter in the search bar, you can type “b:” to search assets with given AssetBundle name.

  • Some restrictions:

  • Don’t allow mark one asset into multiple AssetBundles.

  • You can only set a relative path as the AssetBundle name.

  • You cannot mark scripts into AssetBundles.

  • You cannot mark scene asset and normal asset in a same AssetBundle.

  • API to mark the asset into AssetBundle

  • You can use AssetImporter.assetBundleName to set the AssetBundle name.

  • Simple APIs to build AssetBundles, BuildPipeline.BuildAssetBundles().These APIs are pretty simple, you only need to provide:

  • Output path for all the AssetBundles.

  • BuildAssetBundleOptions which will be described later.

  • BuildTarget which is same as before.

  • Also have one overloaded version to provide an array of AssetBundleBuild which contains one map from assets to AsssetBundles. This provides flexibility to you, you can set your mapping information by script and build from it. And this mapping information won’t break/replace the existed one in the asset database.

  • APIs to manipulate AssetBundle names in the asset database

  • AssetDatabase.GetAllAssetBundleNames() which returns all the AssetBundle names in the asset database.

  • AssetDatabase.GetAssetPathsFromAssetBundle to return the asset paths marked in the given AssetBundle.

  • AssetDatabase.RemoveAssetBundleName() which removes a given AssetBundle name in the asset database.

  • AssetDatabase.GetUnusedAssetBundleNames() which returns the unused AssetBundle names.

  • AssetDatabase.RemoveUnusedAssetBundleNames() which removes all the unused AssetBundle names in the asset database.

  • AssetPostProcessor.OnPostprocessAssetbundleNameChanged callback which will be called if user change the AssetBundle name of an asset.

  • BuildAssetBundleOptions

  • CollectDependencies & DeterministicAssetBundle are always enabled.

  • CompleteAssets is ingored as we always start from assets rather than objects, it should be complete by default.

  • ForceRebuildAssetBundle is added. Even there is no change to the assets, you can force rebuild the AssetBundles by setting this flag.

  • IngoreTypeTreeChanges is added. Even type tree changes, you can ignore the type tree changes with this flag.

  • DisableWriteTypeTree conflicts with IngoreTypeTreeChanges. You can’t ignore type tree changes if you disable type tree.

  • Manifest file. We generate the manifest file for every AssetBundle which contains the following information:

  • The manifest file is next to the AssetBundle.

  • CRC

  • Asset file hash. A single hash for all the assets included in this AssetBundle, only used for incremental build check.

  • Type tree hash. A single hash for all the types included in this AssetBundle, only used for incremental build check.

  • Class types. All the class types included in this AssetBundle. These are used to get the new single hash when doing the type tree incremental build check.

  • Asset names. All the assets explicitly included in this AssetBundle.

  • Dependent AssetBundle names. All the AssetBundles which this AssetBundle depends on.

  • This manifest file is only used for incremental build, not necessary for runtime.

  • Single manifest file. We generate a single manifest file which includes:

  • All the AssetBundles.

  • All the AssetBundle dependencies.

  • Single manifest AssetBundle. It only contains an AssetBundleManifest object which has following APIs:

  • GetAllAssetBundles() which returns all the AssetBundle names in this build.

  • GetDirectDependencies() which returns the direct dependent AssetBundle names.

  • GetAllDependencies() which returns all the dependent AssetBundle names

  • GetAssetBundleHash(string) which returns the hash for the specified AssetBundle.

  • GetAllAssetBundlesWithVariant() which returns all the AssetBundles with variant.

  • AssetBundle loading APIs changed, now we have:

  • AssetBundle.GetAllAssetNames(). Return all the asset names in the AssetBundle.

  • AssetBundle.GetAllScenePaths(). Return all the scene asset paths if it’s a streamed scene AssetBundle.

  • AssetBundle.LoadAsset(). Load asset from AssetBundle.

  • AssetBundle.LoadAllAssets()

  • AssetBundle.LoadAssetWithSubAssets()

  • Asynchronous version also provided

  • We won’t return component type any more, please load the game object first and then look up the component on the object.

  • Typetree is written to the AssetBundle by default. The only exception is Metro as it has different serialization solution.

The above is the basic usage of how to use the new AssetBundle build system. What can you benefit from it?

  • No complex building script any more.

  • Unity handles the dependencies.

  • This means you don’t need to handle the dependencies by using PushAssetDependencies/PopAssetDependencies functions, as Unity knows all the dependencies and handles this for you. This can reduce a lot of your efforts.

  • Incremental build check which means you only need to rebuild the AssetBundle which actually change. This includes two parts:

  • Incremental build check for asset file changes. We generate a single hash for all the assets in the AssetBundle. Only when the assets in the AssetBundles actually change, we will do the rebuild.

  • Incremental build check for type tree changes. We also generate a single hash for the type trees in the AssetBundle. By default, we will rebuild the AssetBundle if type tree changes, but you can ignore the type tree changes by setting IgnoreTypeTreeChanges flag.

  • Don’t force rebuild all the AssetBundles on the dependency chain.

  • We change the way how we store dependent objects, this allow you not rebuild all the AssetBundles on the dependency chain.

  • Let’s have an example, we have a cube prefab which has a material which has a texture. If we mark the cube prefab into CubeAssetBundle, and mark the material into MaterialAssetBundle, then we change the texture on the material. In the old build system, we need to rebuild both the CubeAssetBundle and MaterialAssetBundle, as we need to rebuild the dependent objects. But in the new build system, we only need to rebuild the MaterialAssetBundle without rebuilding CubeAssetBundle.

Btw: The new and the old build systems will coexist for a while, PLEASE DON’T MIX THEM WHEN YOU’RE BUILDING ASSETBUNDLES.

AssetBundle Variant

Another thing I want to describe a little more is AssetBundle variant. From Unity 5.0 b21, we have better AssetBundle variant support in the new build system, which can be used to achieve the same result as virtual assets.

For example, you can set AssetBundle as variants like “MyAssets.hd”, “MyAssets.sd”(Make sure the assets exactly match in these two AssetBundles). The objects in these two variant AssetBundles will have the exactly same internal IDs which is ensured by the Unity build pipeline. So these two variant AssetBundles can be switched out arbitrarily with AssetBundles of different variant extension at runtime.

Then how to set the AssetBundle variant?

  • From UI. From Unity 5.0 b21, beside the AssetBundle Name UI, we add one more UI to set the variant name of the AssetBundle
  • AssetImporter.assetBundleVariant. Except UI, you can also set the AssetBundle variant from script.

The full AssetBundle name will be the combination of the AssetBundle name and the variant name. For example, if you want to add “MyAssets.hd” as a variant AssetBundle, you should set the AssetBundle name to “MyAssets” and AssetBundle variant to “hd”. And the final AssetBundle is “MyAssets.hd”.

But if you only set the AssetBundle name like “MyAssets.hd”, then it’s just a normal AssetBundle which is not variant AssetBundle. And apparently “MyAssets”+“hd” and “MyAssets.hd”+”” cannot coexist as they lead to the same full AssetBundle name.

Btw: It’s not compatible with the Editor simulation.

Demo

Based on the new build system, we also made a demo to demonstrate the usage of current AssetBundle system. You can download the demo at the below link, let me know if you can’t access it. And please based on Unity 5.0 b21 to run this demo.

[EDIT]

This is the up-to-date AssetBundle Manager Demo:
http://unity3d.com/learn/tutorials/topics/scripting/assetbundles-and-assetbundle-manager?playlist=17117

This link is obsolete:
http://files.unity3d.com/vincent/assetbundle-demo/users_assetbundle-demo.zip

[/EDIT]

It demonstrates:

  • How to build AssetBundles in the new build system.
  • How to use the single manifest AssetBundle.
  • Automatic AssetBundle dependency resolving, loading & unloading.
  • Editor simulation. With it enabled, you can use AssetBundles in Editor play mode without actually building them.
  • Optional setup where to download all AssetBundles.
  • Build pipeline build integration. Script to build the AssetBundles and copy them to StreamingAssets folder, then they can be packed into the player data when you’re building the player. Please use the “AssetBundles/Build Player” to build the player data.
  • New version of WWW.LoadFromCacheOrDownload and feed 128 bit hash to it when downloading. You can get the hash from the single manifest AssetBundle.
  • AssetBundle variant to achieve the same result as virtual assets. (It’s not compatible with the Editor simulation.)

Please refer to the README file in the demo project to get more details on this.

Any feedback are appreciated.

8 Likes

Assets/ScriptsForAssetBundleSystem/AssetBundleManager.cs(168,69): error CS1061: Type UnityEngine.AssetBundleManifest' does not contain a definition for GetAllAssetBundlesWithVariant’ and no extension method GetAllAssetBundlesWithVariant' of type UnityEngine.AssetBundleManifest’ could be found (are you missing a using directive or an assembly reference?)

Thanks for this info Vincent!

I sent an email to Unity support a few days ago about this info specifically. For now I had to make do with watching your UNITE presentation and taking screenshots of relevant info.

I have a couple of questions/feature requests about the AssetBundle system in its current state:

  • Versioning AssetBundles Question. So right now with WWW.LoadFromCacheOrDownload you can pass in the Hash 128 or version number, and if Hash 128 doesn’t match (or the version number is higher) then the new AssetBundle will be put into the cache. From my testing, every time I build a new bundle it will be added to the cache and over time my 4gb cache (on iOS/Android) will eventually fill up and then start to delete old unused bundles out of the cache.
    The problem I face is I don’t want my cache to fill up with old bundles, I would much rather be able to tell it to overwrite the old bundle with the new one. This way I’m not filling up the cache with asset bundles I won’t use.

  • The other question I have is regarding loading from AssetBundles, Probably sort of more of a feature request. So currently to load an asset from an AssetBundle I have to use the AssetBundle Name and the Asset’s Name that is contained within.
    like this:

//Load Bundle
WWW www = [WWW.LoadFromCacheOrDownload(assetBundleServerLocation](http://WWW.LoadFromCacheOrDownload(assetBundleServerLocation) + assetBundleName, manifest.GetAssetBundleHash(assetBundleName))

AssetBundle loadedAssetBundle = www.assetBundle;

//Load Asset
Object obj = loadedAssetBundle.LoadAsset(assetName);

So this requires anything that loads from an AssetBundle to have to know the AssetBundle name and Asset name. This reliance on strings from my previous experience can cause headaches. What happens when I change the name of my AssetBundle? Now I have to find all the things loading from that AssetBundle using a string and change them to the new one. Or if I change the name of a Asset, then I have to update the string names in the same way. So instead I have thought of a way to pass in the GUID of a asset then the AssetBundle system will lookup in a dictionary for you what the AssetName is and what AssetBundle it is in, the values are then the AssetBundleName and AssetName. You could then use these values to do the LoadFromCacheOrDownload and LoadAsset. This also means that your download system won’t break if bundles are renamed or assets are renamed.
This system would require a manifest to hold the GUID to AssetBundleName to AssetName relation for the lookup.

Then for the part of making the GUID readable and human writable in the Inspector I have created a attribute which can be used to drag and drop an object then use that objects GUID as a string. Here is my code for this Attribute Dropbox

This functionality of finding an AssetName and AssetBundleName from a GUID at runtime would be a big help and ensure that when AssetBundles are renamed or Assets are renamed that nothing breaks.

Thanks!
Tim

Please use b21.

Ahh of course…i forgot that i still use B20…

Hi Vincent,

Thanks for posting this and all your hard work on Asset Bundles.

What about packing the sprite sheets we make with Sprite Packer into the Asset Bundles? There isn’t any way to mark them to be packed.

It seems like using Sprite Packer prevents you from gaining the benefit of using asset bundles… or using asset bundles prevent you from gaining the benefits of the sprite packer.

All you need to do in this case is mark the assets that are being shared into a specific asset bundle. Once you do that the system automatically records the dependencies for you.

It does require you to mark them to be belong to a specific asset bundle but this is the only way we could make the system a full incremental build system.

For starters we now provide a simple asset bundle loading system that handles all of this for you. Due to the new API’s it greatly simplifies things and provides builtin asset bundle simulation API.

Over time we might include this higher level API which we now provide through scripts into the product in a more builtin way, but for now at the very least all the code is already written for you with a simple high level API and you can even go in and tweak for specific needs.

I strongly suggest you check out the demo project and get a feel for it.

Thanks for posting this, it’s very helpful for the project that I’m working on. I seem to be having some trouble with download link though the host is not resolving, is anyone else having these issues?

Edit:
No longer an issue, was a DNS lookup issue on my end.

I have a quick question, I want to try out the sample project where the bundle is online.

So in order to do that, do I just change the kAssetBundlesPath = “/AssetBundles/”; at BaseLoader.cs to the url that I’m hosting the bundles?

Actually, the requirement makes sense to me. Maybe an API like Caching.RemoveFromCache(string, Hash128) will help you. But I’m not sure if it’s gonna happen in 5.0 cycle.

We will think about this to see if there is a way to feed this design into our asset pipeline. Thanks for the valuable feedback.

Thanks
Vincent

Yes. Please try it and let me know how it works.

It’s a little different for Sprite Packer, the result of packing is not an asset. It will be written to Project\Library\AtlasCache as temporary data, and be built to the player data. So currently there is no way to build it to AssetBundle.

We need to more investigation to find a way which can unify the building of player data and AssetBundles. Thanks for raising this issue.

1 Like

I’ve uploaded the testbundles to my dropbox account, but I have no luck in displaying them in the actual device. The scene just loads but nothing else. (I’m using an adhoc provisioning instead of a development provisioning)

When I tried running it in the simulator I got a crash, a run time error I think.

(Filename: /Users/builduser/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebug.gen.cpp Line: 56)

(lldb)

I think ideally the API, Caching.RemoveFromCache(string, Hash128) could also do Caching.RemoveFromCache(string) //without the Hash128. Because then I don’t have to keep track of previous Hashes somewhere, I can just clear out any AssetBundles that have that name. With the Hash version I would have to store on the users device what the current hashes for each bundle they have is.

Your problem is solved already for you with this new Asset Bundle system by the manifest file. If your atlas is in its own bundle, than every one of your ui prefab bundles will reference it as a dependency and only download it once.

Hi Vincent,

Just to clarify – we can’t currently use atlases generated by the Sprite Packer in Asset Bundles? I was really hoping we could make use of Asset Bundles to support multi-resolution / SD vs. HD sprite swapping (in fact, that’s what I thought the variant system was designed for!). No such luck? :frowning:

sounds to me like its current focus is things marked as textures not sprites. If you were using texturepacker instead of the sprite packer from unity though you could easily create your own texture sheets and those assets could be marked in this asset bundle system if sprite packer support won’t be available for some time, i dont know how long it would take vincent and the guys to implement it.

2 Likes

Which is fine for stuff that I make for myself independently.

At my job not so much. The problem isn’t the price of TexturePacker… it’s purchasing software not from an approved vender.

ya i understand that for sure, that’s the risk you run though when using beta software where you work. might be some other options for you with external software or something, i’m sure someone somewhere has written a texture sheet program that you can leverage, you just might have to write your own json parser for frame data.

No, it doesn’t work in 4.6 either.