AssetBundle load question

Hi,guys.
I am now puzzled by two assetbundle load questions.
The first one is about the load path of assetbundle.
Here is what unity5.3 manual say about the Application.streamingAssetsPath(http://docs.unity3d.com/ScriptReference/Application-streamingAssetsPath.html):Note that on some platforms it is not possible to directly access the StreamingAssets folder because there is no file system access in the web platforms, and because it is compressed into the .apk file on Android. On those platforms, a url will be returned, which can be used using the WWW class.
Though the manual say assetbundles under the path of Application.streamingAssetsPath can be loaded by WWW class, when tests in unity5.3 with AssetBundle.LoadFromFileļ¼ˆAsyncļ¼‰it turns out that AssetBundle.LoadFromFileļ¼ˆAsyncļ¼‰can also load assetbundle(in lzma and lz4 format ) successly with the given path Application.dataPath + ā€œ!assetsā€.
What puzzles me is that since AssetBundle.LoadFromFileļ¼ˆAsyncļ¼‰ in unity5.3 can load assetbundle located in Application.streamingAssetsPath, why did not the manual metion it?And what problems would we run into if we use AssetBundle.LoadFromFileļ¼ˆAsyncļ¼‰to load assetbundles located in Application.streamingAssetsPath with Application.dataPath + ā€œ!assetsā€?
The second one is about cache files when load assetbundles with WWW.LoadFromCacheOrDownload.
Here is what unity manual say about WWW.LoadFromCacheOrDownload(Unity - Scripting API: WWW.LoadFromCacheOrDownload): AssetBundles are uniquely identified solely by the filename and version number. All domain and path information in url is ignored by Caching.
I did some tests with WWW.LoadFromCacheOrDownload.Two assetbundles with the same name but different path were used:

  • assetbundle1:assets/textures/map/daoju/t_dibiao_01;

  • assetbundle2:assets/meshes/map/daoju/materials/t_dibiao_01;

  • Load assetbundle1 with version 1:WWW.LoadFromCacheOrDownload(assetbundle1,1),here we get the right assetbundle for the first load operation cause there is no cache files at all;

  • Load assetbundle2 with version 1:WWW.LoadFromCacheOrDownload(assetbundle2,1),this is where the problem show up for we donā€™t get assetbundle2 as we espect but assetbundle1;

  • Load assetbundle2 with version 2:WWW.LoadFromCacheOrDownload(assetbundle2,2),here we get assetbundle2 as we espcet;

  • Load assetbundle1 with version 2:WWW.LoadFromCacheOrDownload(assetbundle1,2),as step2, the loaded assetbundle is still assetbundle2.

  • The test result proves that WWW.LoadFromCacheOrDownload works as the manual say:no domain or path information in url but just filename is used to identify the assetbundles that cached in local path.

  • As we know that a lot of resources have the same name but different file type suffix or different path when import resources to unity editor.What puzzles me is that since WWW.LoadFromCacheOrDownload can not handle the situations where assetbundles have same filename but different path why unity did not give a note that developers should be aware of repeat name problem of assetbundles?What did I miss if WWW.LoadFromCacheOrDownload have no such problems?

Hi.

I can you please resummarize your two problems? Weā€™re using Assetbundles successfully by either downloading them or from the streamingAssetsPath.

If I understand you correctly, you have one problem that you have two assetbundles with the same name, but at different locations? Do they contain the same data? If not, why not? An assetbundle can contain serveral data and you should use them that way. E.g.:

myAssetbundle.assetbundle contains:

  • myMaterial
  • myShader
  • my3DModel

So, there is no need for three assetbundles, all with the same name, but being in different folders and containing different data.

Hope that does help.

Yep,I have two different assetbundles with the same name but different locations and different data.These two different assetbundles work seperately so they do not have to be packaged in one same assetbundle.And by the way, when resources come up to hundreds and maybe thousands, itā€™s better to let the script tool to do the assetbundle name works.People who named the resources just follow their habbits, and I name the assetbundles with resourcesā€™ names directly by a script to do all the work.

You have to adjust your script then, either to generate different names, taking the location of the asset into account then, or you put assets with same names into the same assetbundle. Both will work, though Iā€™d go with the latter.

E.g.:

The diablo.assetbundle contains:

  • diablo (mesh)
  • diablo (material)
  • diablo (texture)

Should work. You can then load the assets from the assetbundle by giving the type.

Thanks pahe for the suggestion and with no doubt it will work correctly.
The question is WWW.LoadFromCacheOrDownload wonā€™t return the right assetbundle when assetbundles has the same name and same version but different path.Is this a Unity bug or did we both miss something that can make the situation correct?
And by the way,has any idea about the first question?

If that is the case, I think that would be a bug then and I would report it with the Bug Reporting tool with a small project.
I think though that the problem is more that when accessing the assetbundle, the engine will complain of having already an assetbundle open with the same name.

Not sure what the question is. About AssetBundle.LoadFromFile? Application.StreamingAssetPath mentions that as some platforms there is no direct file access to that path (Android for example). This would cause problems when you try AssetBundle.LoadFromFile as you cannot access the file, but instead have to use the WWW.LoadFromCacheOrDownload function.
For assetbundles loaded from the StreamingAssetPath we use different ways to load the bundles for Android and iOS. Not sure about consoles though, weā€™re not developing for them.

Yes,the question is about AssetBundle.LoadFromFile(Async).Though the manual recommends users to use WWW to load assetbundles located in Application.StreamingAssetPath, I did tests to use AssetBundle.LoadFromFileļ¼ˆAsync) to load assetbundles located in Application.StreamingAssetPath on Android.It really works to be with the path in format of Application.dataPath + ā€œ!assetsā€, not the format of Application.StreamingAssetPath.

When print the two path and see logs on Android, the only main difference is the preffix ā€œjar:file:///ā€:

  • Application.streamingAssetsPathļ¼šjar:file:///data/app/packagename-1.apk!/assets
  • Application.dataPathļ¼š/data/app/packagename-1.apk

It do make defference if AssetBundle.LoadFromFile(Async) could load assetbundles from Application.StreamingAssetPath dirrectly(Even just for Android, not test on IOS yet).For what we know, AssetBundle.LoadFromFile is the fastest way to load assetbundles.

But what the manual say just goes to the other side:ā€œNote that on some platforms it is not possible to directly access the StreamingAssets folder because there is no file system access in the web platforms, and because it is compressed into the .apk file on Android. On those platforms, a url will be returned, which can be used using the WWW class.ā€

Ok, good to know. Weā€™re using WWW.LoadFromCacheOrDownload for Android for local files. I know that it did not work before Unity 5.x, maybe they changed it recently and didnā€™t update the manual then.

That would be a good situation for users on Android if the manualā€™s update were late.But we must take the bad scenario into accout that Unity did not forget the manualā€™s update and AssetBundle.LoadFromFile(Async) wonā€™t work correctly under some situations on Android.Hope Unity Assetbundle guys could take my puzzle away.

1 Like

Keep up updated. Would be nice to get rid of the extra code in our framework.

It is possible to load a bundle from StreamingAssets folder on Android using LoadFromFile[Async].
Itā€™s a bit inconvenient as itā€™s not aligned with Application.streamingAssetsPath usage (shame on us), but we are working on a fix.
Right now the following scheme should work pretty much on all platforms:

public static string GetBundlePathForLoadFromFile(string relativePath)
{
#if UNITY_ANDROID
    var streamingAssetsPath = Application.dataPath + "!assets/";
#else
    var streamingAssetsPath = Application.streamingAssetsPath;
#endif
    return Path.Combine(streamingAssetsPath, relativePath);
}

public static AssetBundle LoadBundleFromStreamingAssets(string relativePath)
{
    return AssetBundle.LoadFromFile(GetBundlePathForLoadFromFile(relativePath));
}
2 Likes

@alexeyzakharov Any ETA on that? 5.5?

Yes. We always land fixes to the ā€œdevā€ branch which is equivalent to 5.5 now.
And then we backport them to ā€œbetaā€ and ā€œstableā€ taking into account complexity/risk and severity of the issue.
This one seems to be safe and could be landed to 5.4 as well. I canā€™t say exact day, but it could take up to 1 month from now.

1 Like

@alexeyzakharov

Thanks for the explanation. It really helps. Hope Unity could add it into the Manuel to make users (especially the greeners) be aware of that they could do assets load this way ( without be confiused with the path like I do).

Hi guys!
The fix has been backported to 5.4 (and is in 5.5)
AssetBundle.LoadFromFile can be used with paths created with Application.streamingAssetsPath on Android as well.

1 Like

It seems still doesnā€™t work on Android from Unity 5.4.0f3. I use source code from demo https://bitbucket.org/Unity-Technologies/assetbundledemo. Here is how to reproduce:

  • Build asset bundle from Assets/AssetBundles/Build AssetBundles.
  • Rename and Move AssetBundles folder to Assets/StreamingAssets folder.
  • Add TestLoadFromFile.cs script to GameObject with following code.
using UnityEngine;
using System.Collections;
using System.IO;

public class TestLoadFromFile : MonoBehaviour
{
    private void Start() {
        AssetBundle materialBundle = AssetBundle.LoadFromFile(GetBundlePathForLoadFromFile("material-bundle"));
        AssetBundle cubeBundle = AssetBundle.LoadFromFile(GetBundlePathForLoadFromFile("cube-bundle"));
        if (materialBundle == null)
        {
            Debug.LogError("Failed to load Material AssetBundle.");
            return;
        }
        if (cubeBundle == null)
        {
            Debug.LogError("Failed to load Cube AssetBundle.");
            return;
        }

        GameObject prefab = cubeBundle.LoadAsset<GameObject>("MyCube");
        Instantiate(prefab);

        cubeBundle.Unload(false);
        materialBundle.Unload(false);
    }

    public static string GetBundlePathForLoadFromFile(string relativePath)
    {
        #if UNITY_ANDROID && !UNITY_EDITOR
        string streamingAssetsPath = Application.dataPath + "!assets/";
        #else
        string streamingAssetsPath = Application.streamingAssetsPath;
        #endif
        return Path.Combine(streamingAssetsPath, relativePath);
    }
}

Iā€™m so sorry. It was my bad. It actually WORKS PERFECTLY. I built asset bundle when target platform was iOS, after that I switched target into Android, build test and failed. I just realised that it mays conflict with platform. I rebuild asset bundle again with Android platform. As you knew, IT WORKS.

Hi rutz!
Glad to hear it works. Also it should work without having #if UNITY_ANDROID block around now.

Thanks @alexeyzakharov .

I have issue with AssetBundle.LoadFromFileAsync block/freeze my UI due to large file loading. However, it is unable to call within a new thread (non-main thread of Unity). Is there any solution for this issue?