Cannot load an Asset Bundle - unity3d

I created an asset bundle from an .fbx file. Then; I use this code for loading it into a very simple unity project
public class k : MonoBehaviour {
public string url;
// Use this for initialization
public string AssetName;
void Start()
{
}
IEnumerator DownloadAndCache(string bundleURL)
{
while (!Caching.ready)
yield return null;
using (WWW www = WWW.LoadFromCacheOrDownload(bundleURL, 1))
{
yield return www;
if (www.error != null)
throw new Exception("WWW download had an error:" + www.error);
AssetBundle bundle = www.assetBundle;
if (AssetName == "")
Instantiate(bundle.mainAsset);
else
Instantiate(bundle.LoadAsset(AssetName));
bundle.Unload(false);
}
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.D))
StartCoroutine(DownloadAndCache(url));
}
}
but always is having the next issue
and I don't understand. Since i'm passing a valid local url in the next format :
file:///c:/asset/robot.unity3d
please help

A file with a unity3d extension isn't usually an AssetBundle.
To have an AssetBundle with the model in it you have to:
Import the model in Unity
Select the imported model so you see its properties in the Inspector
At the bottom of the Inspector there is a little interface to create and select AssetBundles (this way the model will be assigned to the selected AssetBundle)
After assigning every asset to their AssetBundle, you need to build the Bundles
Put the bundles files on a server or in the StreamingAssets folder and use their URL
AssetBundle management in Unity is still a painfull process so I suggest you to thoroughly read the Guide to AssetBundles and Resources.
There is also an AssetBundleManager here but I find it's code is a mess.
It's buggy and almost impossible to decipher: I ended up writing my own so I can't really suggest you to use it yet (I linked it because it might get better in the future).

Try calling bundle.GetAllAssetNames() to see what is inside the bundle before trying to instantiate anything.
AssetBundle bundle = www.assetBundle;
foreach(var name in bundle.GetAllAssetNames()){
Debug.Log(name);
}
mainAsset may be null depending on how the AssetBundle was created, so maybe that is what happening here, does it gives you the null exception if you try loading assets by name?

Related

How can i load asset bundle which don't know the name of asset?

I want to load and instantiate asset from my asset bundle, but in unity 5.+ i can do it with code like this:
Note: my assetbundle have one asset inside itself, like:
AssetBundle myLoadedAssetBundle;
public string path;
void Start()
{
LoadAssetBundle(path);
}
void LoadAssetBundle(string bundleUrl)
{
myLoadedAssetBundle = AssetBundle.LoadFromFile(bundleUrl);
Debug.Log(myLoadedAssetBundle == null ? "Faild To Load" : "Succesfully Loaded!");
Debug.Log(myLoadedAssetBundle.mainAsset.name);
Instantiate(myLoadedAssetBundle.mainAsset);
}
}
actually even i use
Debug.Log(myLoadedAssetBundle.mainAsset.name);
to log name of mainasset of my assetbundle!
but in unity after 5+ , they say mainasset is obsolete.
my questions is:
1- How can i load asset bundle which don't know the name of asset?
2- How Instantiate or assign sprite which loaded of assetbundle ?
According to the AssetBundle documentation, there is now the ability to call GetAllAssetNames() to return a list of all asset names in a bundle as a string array. You can load the assets from the bundle via a for loop with those asset names.
Alternatively, if you are guaranteeing to only have 1 asset per bundle you can simply grab the string at index 0 (not recommended).
Additionally, you can load the assets without knowing the names by using LoadAllAssets() which returns an array of the specific type (in your case you would specify Sprite).
You could try something like this: (Note - You will need to know your directory path to each asset, here, I'll make some stuff up as an example)
private List<GameObject> assetBundle = new List<GameObject>();
private GameObject asset1 = Resources.Load("Weapon1") as GameObject;
private GameObject asset2 = Resources.Load("Weapon2") as GameObject;
private GameObject asset3 = Resources.Load("Weapon3") as GameObject;
private void Start()
{
assetBundle.Add(asset1);
assetBundle.Add(asset2);
assetBundle.Add(asset3);
}
Now you can access them from the list by element whenever you wish. However, I'm not 100% certain that Resources.Load() will work for what you're trying to do. I am about 65% - 70% though so I answered. Hope it helps!
Here's my solution,
IEnumerator LoadBundleFromDir(string bundleUrl)
{
//which type of asset i want load
GameObject model;
AssetBundleCreateRequest bundleRequest = AssetBundle.LoadFromFileAsync(bundleUrl);
yield return bundleRequest;
AssetBundle localeAssetBundle = bundleRequest.assetBundle;
Object[] allBundles = localeAssetBundle.LoadAllAssets();
foreach (Object item in allBundles)
{
if (item.GetType() == typeof(GameObject))
{
AssetBundleRequest assetRequest = localeAssetBundle.LoadAssetAsync<GameObject>(item.name);
yield return assetRequest;
model = assetRequest.asset as GameObject;
localeAssetBundle.Unload(false);
break;
}
}
}

Alternative to AssetDatabase.LoadAssetAtPath for any path?

Currently I am using the following piece of code to load Textures from image files.
Texture my_pic = (Texture) AssetDatabase.LoadAssetAtPath(path, typeof(Texture));
Unfortunately this method doesn't work if the target path isn't in the Asset/ folder. I was wondering how I would load an image, given some absolute path of the form
/Users/Alan/SomeFolder/SomePic.png
(note that I am currently writing a custom Unity editor plugin by extending EditorWindow if that matters)
AssetDatabase is an Editor-only class.
Furthermore, it can only read assets in the /Assets directory (you know, the ones that are known to the asset database).
If you want to read any file on the file system, you need to use the System.IO classes.
Here is some code that will open a unity file dialog, and load the selected texture into a material of the attached object.
string path = EditorUtility.OpenFilePanel("Load an image", "", "png");
if (string.IsNullOrEmpty(path)) {
return;
}
// Load the images bytes from file (this is a synchronous call!)
byte[] bytes = null;
try {
bytes = System.IO.File.ReadAllBytes(path);
} catch (System.Exception e) {
Debug.LogError(e.Message);
return;
}
// Load the bytes into a Unity Texture2D
Texture2D _tex = new Texture2D(2,2);
_tex.LoadImage(bytes);
// Apply this texture to the object
Renderer r = (target as Component).gameObject.GetComponent<Renderer>();
if (r != null) {
r.material.SetTexture("_MainTex", _tex);
}
The last part, just for demonstration, will work only on a script derived from Editor because it uses target to find the attached renderer. It's up to you to decide what to do with the texture in your EditorWindow script.
Also, remember to explicitly call DestroyImmediate on your texture when you no longer need it, as you may end up with a memory leak in your editor code.
You can use UnityWebRequestTexture
var www = UnityWebRequestTexture.GetTexture("file:///Users/Alan/SomeFolder/SomePic.png");
www.SendWebRequest();
while(!www.isDone)
continue;
var texture = DownloadHandlerTexture.GetContent(www);

Unity assetbundle scene unload

I have created few assetbundle scenes for my project. Now I am downloading the assetbundles and able to load scenes. Here the problem is that when I run a scene and exit from that and try to reload the same scene once again, it is giving an error like
"The Assetbundle mywebsite.com/bundles/assetbundle.unity3d can't be loaded because another AssetBundle with the same files is already loaded."
Im not able to open the scene for second time. Can anyone tell the problem and help me to resolve?! Thanks in advance.
Im adding the code here:
IEnumerator sceneLoad()
{
WWW www = WWW.LoadFromCacheOrDownload(myurl,version);
while (!www.isDone)
{
msg.text = "Downloading...";
float progress = Mathf.Clamp01 (www.progress / .9f);
progressslide.value = progress;
float val = progress * 100f;
double value = System.Math.Round (val, 2);
progresstext.text = value + "%";
Debug.Log ("Progress " + progresstext.text);
yield return null;
}
bundle = www.assetBundle;
msg.text = "Opening Scene...";
progressslide.gameObject.SetActive (false);
progresstext.gameObject.SetActive (false);
string[] scenepath = bundle.GetAllScenePaths ();
Debug.Log (scenepath [0]);
var async = SceneManager.LoadSceneAsync(System.IO.Path.GetFileNameWithoutExtension (scenepath [0]));
yield return null;
bundle.Unload (false);
}
The above code is perfectly working on unity engine in my pc but when I build apk and run on phone, the progress bar is not working but bundle is downloading and scene is opening. Later when I exit the scene, comes to my app main page and again open the same scene, it was showing the error as
"The Assetbundle mywebsite.com/bundles/assetbundle.unity3d can't be loaded because another AssetBundle with the same files is already loaded."
I am using Vuforia in the downloaded scene.
You should unload the loadded asset bundle when you exit the scene.
Maybe you will find this proper asset bundle guide.

Unity5 Building Asset Bundles with scenes

I am trying to create an asset bundle with scenes. This is what I did in unity4
[MenuItem("Bundle/Create ios Scene SceneLoader")]
static void iosBuild(){
string[] levels = new string []{"Assets/Scenes/01 SceneLoader.unity", "Assets/Scenes/02 Level1.unity","Assets/Scenes/02 Level2.unity" ,"Assets/Scenes/02 Level3.unity"};
BuildPipeline.BuildStreamedSceneAssetBundle( levels, "Assets/Bundles/bundle-ios.unity3d", BuildTarget.iOS);
}
After that I load my bundle via this code:
using(WWW www = WWW.LoadFromCacheOrDownload (url, 0)){
while(!www.isDone){
status.text = "loading \n" + (www.progress * 100).ToString() + "%";
yield return null;
}
yield return www;
//check if server response is an error
if (www.error != null){
throw new Exception("WWW download had an error: " + url + " " + www.error);
}
//Load the asset bundle
AssetBundle bundle = www.assetBundle;
//obsolete bundle.LoadAll();
bundle.LoadAllAssets();
Application.LoadLevel ("01 SceneLoader");
}
This code worked in unity4, but now, when I load my Scene, all the script references are missing. Objects are in the scene but no scripts. Also, unity tells me that BuildStreamedSceneAssetBundle is obsolete. So my question is, why aren't my script references in the core scene ? So that when I load an asset bundle, all the scripts aren't missing. Also my NGUI Atlas that I use in the loaded scene is missing.
Would be glad if someone has an idea!
EDIT: the first string in "levels" will have all script references. How is that possible ?
I think this problem is unity bug.
My project has same problem.
I found solution, but it's very inconvenient.
If you must use scene asset bundle,
make one asset bundle per one scene.
string[] level1 = new string []{"Assets/Scenes/01 SceneLoader.unity"};
string[] level2 = new string []{"Assets/Scenes/02 Level1.unity"};
.....
BuildPipeline.BuildStreamedSceneAssetBundle( level1, "Assets/Bundles/bundle-ios1.unity3d", BuildTarget.iOS);
BuildPipeline.BuildStreamedSceneAssetBundle( level2, "Assets/Bundles/bundle-ios2.unity3d", BuildTarget.iOS);
.....
I used "BuildPipeline.BuildAssetBundles" func at Unity5.
But I think that "BuildPipeline.BuildStreamedSceneAssetBundle" and "BuildPipeline.BuildAssetBundles" is similar.

Unable to delete downloaded asset bundles

Currently, I have uploaded collections of my scenes to a server in an asset bundle form. However, I'm unable to to delete the asset bundles that I have downloaded from the game before. I tried using
WWW www = WWW.LoadFromCacheOrDownload (url, 1);
yield return www;
// Handle error
if (www.error != null)
{
Debug.LogError(www.error);
yield return true;
}
else
{
Debug.Log("Loaded");
}
AssetBundle assetBundle = www.assetBundle;
assetBundle.LoadAll ();
www.assetBundle.Unload (false);
www.Dispose ();
But I got these errors:
Caching class is responsible for Unity's download cache, and Caching.CleanCache will help to delete all asset bundles you have downloaded.