Unity assetbundle scene unload - unity3d

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.

Related

Multiple Asset Bundle Download Cache Problem

I'm using UnityWebRequestAssetBundle.GetAssetBundle(url, bundleData.version, bundleData.crc); system and I can successfully download and use bundleAssets online. But when I want to download multiple bundle assets and save them to use offline for later I have a problem.
I have 2 files for example, 'A' and 'B'.
Case 1: When I download A and go offline I can load A anytime even I close the app. But when I want to download B and come back to A can't load A again because it deletes cache for some reason and tries to download it again.
Case 2: When I download A and B together and go offline, if I load B it loads. But if I try A it can't load and needs internet connection. After that when I try to load B again I loose package so it needs internet connection again.
So basicly I want to download multiple asset bundles and I want to use them whenever I want. How can I solve this problem? Thanks.
Code example:
using UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(url, bundleData.version, bundleData.crc);
yield return uwr.SendWebRequest();
bundle = DownloadHandlerAssetBundle.GetContent(uwr);
Debug.Log(bundle);
if (bundle==null)
{
Debug.Log("COULDN'T CONNECT TO URL");
callback(null);
}
else
{
Debug.Log("FOUND AT SEARCH!");
// Get downloaded asset bundle
bundle = DownloadHandlerAssetBundle.GetContent(uwr);
Sprite sprite = isDiff ? bundle.LoadAsset<Sprite>(levelText + "Diff") : bundle.LoadAsset<Sprite>(levelText);
callback(sprite);
}
I solved my issue by saving images to persistentFolder.
I write image to disk first by Texture2D.EncodeToJPG();
private void writeImageOnDisk(Sprite sprite, string fileName)
{
Texture2D texture = DeCompress(sprite.texture);
byte[] textureBytes = texture.EncodeToJPG();
File.WriteAllBytes(Application.persistentDataPath + "/" + fileName+".jpg", textureBytes);
Debug.Log("File Written On Disk!");
}
To EncodeToJPG image must be Read/Write enabled before having AssetBundles and you should decompress them first, I found solution from this topic.
private Texture2D DeCompress(Texture2D source)
{
RenderTexture renderTex = RenderTexture.GetTemporary(
source.width,
source.height,
0,
RenderTextureFormat.Default,
RenderTextureReadWrite.Linear);
Graphics.Blit(source, renderTex);
RenderTexture previous = RenderTexture.active;
RenderTexture.active = renderTex;
Texture2D readableText = new Texture2D(source.width, source.height);
readableText.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
readableText.Apply();
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(renderTex);
return readableText;
}
And finally you can load image with this code:
private Sprite loadImageFromDisk(string fileName)
{
string dataPath = Application.persistentDataPath + "/" + fileName + ".jpg";
if (!File.Exists(dataPath))
{
Debug.LogError("File Does Not Exist!");
return null;
}
byte[] textureBytes = File.ReadAllBytes(dataPath);
Texture2D loadedTexture = new Texture2D(2048,2048,TextureFormat.ARGB32, false);
loadedTexture.LoadImage(textureBytes);
Sprite spr = Sprite.Create(loadedTexture, new Rect(0f, 0f, loadedTexture.width, loadedTexture.height), new Vector2(.5f,.5f), 2048); // 2048 is pixel per unit if you have a custom pixelPerUnit value you should set it here. Or you will see only some part of pixels of image.
spr.name = fileName;
return spr;
}
I hope this will work for you guys. This is how I store my images after downloading assetbundles and how I call them in game.

Imaged loaded via new WWW doesn't display in a build, but it does in the player

I'm loading a .jpeg file in at runtime from disk, it works absolutely fine in the player but when I build the project the texture being loaded in via WWW doesn't display - no errors. It suggests a format issue, but like I said it renders as expected in the player:
Unit doc: https://docs.unity3d.com/ScriptReference/WWW.LoadImageIntoTexture.html
private IEnumerator SetMaterialImage(string path)
{
Texture2D tex;
tex = new Texture2D(4, 4, TextureFormat.RGB24, false, true);
WWW www = new WWW(path);
if (!string.IsNullOrEmpty(www.error))
{
Debug.Log("ERROR REDNERING IMAGE --- " + www.error);
}
while (!www.isDone) yield return null;
if (www.isDone)
{
Debug.Log("WWW,ISDONE = TRUE");
Shader shader = Shader.Find("Standard");
www.LoadImageIntoTexture(tex);
GetComponent<Renderer>().material.mainTexture = tex;
GetComponent<Renderer>().material.shader = shader;
}
}
Edit: please don't suggest the Resources folder - this particular application must load from disk
I was unable to locate any Unity documentation that explains why this scenario differed between Player and Build, however I was able to confirm that:
GetComponent<Renderer>().material.mainTexture = tex;
Renderer>().material.shader = shader;
Should have been declared in the opposite order:
Renderer>().material.shader = shader;
GetComponent<Renderer>().material.mainTexture = tex;
Edit: Credit #Programmer 'The reason that code work in the Editor is because the Editor remembers which Shader or Texture is assigned to a material. So, when you change the shader, it uses the old texture'

Unity scene empty after loading Asset Bundles

I'm creating an AssetBundle in Unity containing one scene with the following code:
string[] scenes = {"Assets/Scenes/main.unity"};
BuildPipeline.BuildStreamedSceneAssetBundle( scenes , "main.unity3d", EditorUserBuildSettings.activeBuildTarget);
I have an empty intro scene that loads the main scene at the start of the app on iOS:
using (WWW www = WWW.LoadFromCacheOrDownload (url + "main.unity3d", 0)) {
while (!www.isDone) {
yield return null;
}
//check if server response is an error
if (www.error != null) {
throw new Exception ("WWW download had an error: " + www.error);
}
//Load the asset bundle
AssetBundle bundle = www.assetBundle;
bundle.LoadAllAssets ();
}
Application.LoadLevel ("main")
The problem is that the main scene is correctly loaded, but the 3D objects in it ( FBX files + textures ) can not be seen . The main scene has no scripts , only 3D objects , including simple cubes of Unity , which have been stored as prefabs in the Assets folder .
What could be wrong , that the 3D data are not displayed ? The Asset Bundle itself has around 20MB , which by size definitely the 3D objects should contain . I use Unity 5.2.4 and it is only a problem in iOS , Android is working and the objects are displayed normally .
I found the solution. You have to turn off "Strip Engine Code" in Unity

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.

Load Scene in AssetBundle and Unload

I load a scene in my AssetBundle like this:
IEnumerator AsyncLoad ()
{
using (var www = new WWW("file://" + Application.dataPath + "/AssetBundles/scenes"))
{
yield return www;
var bundle = www.assetBundle;
Application.LoadLevel("Scene1");
bundle.Unload(false);
}
}
The problem is sometimes Application.LoadLevel("Scene1"); works fine and sometimes Scene1 is empty. What's wrong here?
Side note: I noticed LoadLevel destroys the current scene before loading, so the lines after LoadLevel are not being executed (since the script was destroyed). As I need to unload the asset bundle in order to use it again another time, what's the solution?
Unity 5
you want to use dontdestroyonload on the object that has this loading script attached
http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
Application.LoadLevel will postpone load sceneobjects next frame, so you need to postpone unload AssetBundles.
IEnumerator AsyncLoad (){
using (var www = new WWW("file://" + Application.dataPath + "/AssetBundles/scenes")){
yield return www;
var bundle = www.assetBundle;
Application.LoadLevel("Scene1");
yield return null; // THIS LINE IS ADDED
bundle.Unload(false);
}
}
This may work for you.