Get Assetbundle name before loading - unity3d

I'm working on a project where the user can load assetbundles during runtime, so we only have limited control over what assetbundles are used. Because of that, we have to be careful when we load multiple assetbundles since AssetBundle.LoadFromFile(bundlePath) returns null if a bundle with the same name is already loaded. It will write this Error to the Log:
The AssetBundle 'testbundle' can't be loaded because another AssetBundle with the same files is already loaded.
The main problem now is that I couldn't find a way to get the name of the assetbundle in the file without loading the assetbundle. Using the filename is a workaround, but won't work if people rename the assetbundle file.

We ended up with a very ugly workaround:
Before we load an assetbundle we have to call UnloadAllAssetBundles. This works because there will never be a name clash. But also makes caching impossible, and we load the same bundle multiple times.

Related

Unity Asset Bundles Rebuilding with Old Data

I have a mobile project which displays various AR experiences to the user via a mobile application. This application is made in Unity.
Alongside this Unity project we have a second project that stores asset bundles exclusively. Each AR experience is a prefab marked with a unique asset bundle name. These bundles are stored online and downloaded into the main mobile application when relevant. We're having issues with having these bundles correctly update, when changing things on the prefab such as scale or rotation they aren't reflected in the rebuilt asset bundle.
Here's a look at the process we're using for rebuilding assets, It's only a simple script.
[MenuItem("Spiff/Build AssetBundles")]
static void BuildAllAssetBundles()
{
// BuildPlatformBundles(BuildTarget.iOS);
BuildPlatformBundles(BuildTarget.Android);
}
static void BuildPlatformBundles(BuildTarget platform)
{
// We convert the passed platform enum to a string.
string platformFolder = platform.ToString();
string assetBundleDirectory = "Assets/AssetBundles/" + platformFolder;
// Build our bundles out to the relevent platform specific folder.
if (!AssetDatabase.IsValidFolder(assetBundleDirectory))
{
AssetDatabase.CreateFolder("Assets/AssetBundles/", platformFolder);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, platform);
}
Currently we use 'BuildAssetBundleOptions.None' We've also tried the ForceRebuild flag but this has no effect. Am I correct in assuming that Unity has some sort of internal cache it keeps for assets bundles? If so can we clear this somehow so I can ensure 100% that the bundle I am building is going to be the most up to date based on the prefab tagged with it?
Loaded Assetbundles are indeed cached, and will remain so until AssetBundle.Unload() has been called to free up all memory accociated with the asset.
After the asset has been unloaded a newer version of the assetbundle can be downnloaded and instantiated with the new values (Assuming the file downloaded has all the updated information), else it will load the data from cache if available.
On a side note: It seems like you're still using the old assetbundle pipeline. Unity has a plugin tool that makes the assetbundle workflow considerably easier called the assetbundle browser found here. It comes with a way easier UI for building bundles and inspecting bundles, open source and a very customisable pipeline. It may be worth checking out.
Like remy_rm mentioned, do give the Unity Asset Bundle Browser tool a try. It gives more control over what assets are in the bundle.
Your problem can be solved if you ensure two things:
1- When you make changes to a prefab and create a new bundle, is it indeed created with the said changes? (again using the tool would make checking this easier)
2- The bundles you are downloading in the main application are the new ones and not the old cached ones. In Unity Webgl for instance, you need to clear the browser cache to be 100% sure that the application downloads the new asset bundles and doesn't use the old ones in browser cache.

Unity Asset Bundles - Which Files Do I Deploy?

I have created some asset bundles from my Unity assets using the directions given in the Unity documentation section on AssetBundle Workflow. After running the "Build AssetBundles" command, each asset bundle results in four files: myasset, myasset.meta, myasset.manifest, myasset.manifest.meta.
Now I am ready to deploy these bundles to a web server and implement downloading/caching in my Unity project. I have found numerous examples such as this that show the download URL to be a single file with a .unity3d extension. This is leading me to conclude that I am missing a step - I assume that all four of my files will be required by the app and that I have to do something to combine them into a .unity3d file first.
What file(s) do I need to deploy? Are there any additional steps that I need to take before my file(s) are ready to upload? Thanks in advance for any advice!
Just myasset will suffice.
Sometimes people optionally add .unity3d as a filename extension to their Asset Bundles. It is just a community convention, and is completely optional. Source (copied below)
Vincent-Zhang
Unity Technologies
Just a reminder, we don't have an official file extension ".unity3d" for asset bundle, it's not mandatory. You can use whatever file extension as you want, or without file extension.
But usually people use ".unity3d" as the file extension just because we used it in the official sample code at first time...
Unity creates the .meta files for all assets- you don't have to worry about those. In short, your myasset file is enough. I do not add file extensions to mine. Do note that if you use the strategy shown in the example that you shared that the client will re-download the bundle from the server every time. You need to additionally provide a version number if you want to take advantage of caching. You can see this in some of the method overloads here, the ones that have a Hash128 or uint "version" parameter. Caching is great because you can use the bundle that is already saved on the device next time instead of downloading from the server when no changes have occurred. The version/hash number you provide essentially gets mapped to the file name. Whenever a matching version is found, the file on disk is used. Update the version number to something else when the content changes to force the client to download anew.
You may want to reference the .manifest file for the CRC value listed there. You may have noticed a crc parameter in the link I shared as well. This can be used to ensure data integrity during transmission of the bundle data. You can make sure the downloaded content's CRC matches that of the bundle when you created it.

Unity3D update local assetBundle

In my project, I have a bunch of items stored as assetBundles. In my server, I stored a list of item including their id and version. So ideally, using UnityWebRequest.GetAssetBundle(uri, versionId)I just get the item lists every time I open the app, if first opened, it will download every item; if secondly open, it will only download the one I have updated the version number on the server. Everything is very easy.
But now, I want to store those assetBundles at local first so that people don't need to download with cellular data.Is there an easy way to manage those assetBundles?
You can place the AssetBundles in the StreamingAssets folder. This is what the folder should look like:
Assets/StreamingAssets/
When you build the project, Unity will include the AssetBundles in the build. Of-course, you can use the Resources API but the StreamingAssets folder seems to be more appropriate here.
Once you place the AssetBundles there, you can use Application.streamingAssetsPath and AssetBundle.LoadFromFile to load the AssetBundle.
You can also use the WWW API with Application.streamingAssetsPath to load the AssetBundle.
You 'dont' keep a local text file. you have the version number inside the local bundle. You have a text file on the server. then get the text file, compare that with the version in the bundle and update if necessary.
In the server, you can have an assetbundle with only a textasset to secure that too.
you can build the asset bundles and have them in the streamingAssets folder or anywhere and use AssetBundle.LoadFromFile()

Errors loading scripts on prefabs from asset bundles

I'm currently trying to set up my project to allow users to download mini games post release. Todo this I am trying to use asset bundles to facilitate this, one containing the new games scene and one containing the assets and DLLs for the scripts required. The problem I am having is that when I load the scene or a prefab from the bundle all the attached scripts are still there but a warning says "the associated script can not be loaded. please fix any compile errors and assign a valid script". Is there something obvious that I am missing or do asset bundles not work this way and I'm going to have to rebuild my scene on load?
You can't have the scripts in the asset bundles assigned as references from GameObjects like you normally would. You can only access scripts from asset bundles by loading them with reflection. Then you can programmatically attach them to GameObjects, etc. from there (for example, load the assembly, find your Type, then use AddComponent() on a GameObject with your new loaded type).
See http://docs.unity3d.com/Manual/scriptsinassetbundles.html.
But even if you were to overcome these hurdles, it won't work on Windows Phone and it's against the terms of service of Apple's store, so ...

How to load assets dynamicaly in Unity3D?

What is the proper way to load external assets in Unity3D Webplayer?
My example consists of an empty scene and a button. I have to load an external asset into the scene when user clicks a button. Than i should assign scripts etc, but the question is - i can create an empty object with script, but how to load an external asset into it?
External asset is the file stored on the remote PC, accessible by http or any other protocol.
Unity has the WWW class for accessing data from certain protocols, most notably http like you said above.
http://docs.unity3d.com/Documentation/ScriptReference/WWW.html
If the object returns successfully you can access the data it downloaded. You can access the raw bytes it downloaded and treat the data however you need. Alternatively, you can access it as text or a texture if that is applicable in your situation.
You can have a look at AssetBundles:
https://unity3d.com/fr/learn/tutorials/topics/best-practices/assetbundle-fundamentals
Once the bundle is stored somewhere remotely you can download it using WWW.LoadFromCacheOrDownload and then instantiate specific objects from it.