Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

AssetBundle load question

Discussion in 'Editor & General Support' started by dengqingbin, May 5, 2016.

  1. dengqingbin

    dengqingbin

    Joined:
    Apr 26, 2016
    Posts:
    10
    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(http://...ptReference/WWW.LoadFromCacheOrDownload.html): 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;
      1. 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;
      2. 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;
      3. Load assetbundle2 with version 2:WWW.LoadFromCacheOrDownload(assetbundle2,2),here we get assetbundle2 as we espcet;
      4. 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?
     
  2. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    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.
     
  3. dengqingbin

    dengqingbin

    Joined:
    Apr 26, 2016
    Posts:
    10
    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.
     
  4. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    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.
     
  5. dengqingbin

    dengqingbin

    Joined:
    Apr 26, 2016
    Posts:
    10
    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?
     
  6. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    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.
     
    Last edited: May 7, 2016
  7. dengqingbin

    dengqingbin

    Joined:
    Apr 26, 2016
    Posts:
    10
    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."
     
  8. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    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.
     
  9. dengqingbin

    dengqingbin

    Joined:
    Apr 26, 2016
    Posts:
    10
    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.
     
    pahe likes this.
  10. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    Keep up updated. Would be nice to get rid of the extra code in our framework.
     
  11. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    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:
    Code (CSharp):
    1. public static string GetBundlePathForLoadFromFile(string relativePath)
    2. {
    3. #if UNITY_ANDROID
    4.     var streamingAssetsPath = Application.dataPath + "!assets/";
    5. #else
    6.     var streamingAssetsPath = Application.streamingAssetsPath;
    7. #endif
    8.     return Path.Combine(streamingAssetsPath, relativePath);
    9. }
    10.  
    11. public static AssetBundle LoadBundleFromStreamingAssets(string relativePath)
    12. {
    13.     return AssetBundle.LoadFromFile(GetBundlePathForLoadFromFile(relativePath));
    14. }
     
    developer_gridice and pahe like this.
  12. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
  13. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    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.
     
    pahe likes this.
  14. dengqingbin

    dengqingbin

    Joined:
    Apr 26, 2016
    Posts:
    10
    @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).
     
  15. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    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.
     
    pahe likes this.
  16. rutz

    rutz

    Joined:
    Aug 21, 2013
    Posts:
    51
    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.
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.IO;
    4.  
    5. public class TestLoadFromFile : MonoBehaviour
    6. {
    7.     private void Start() {
    8.         AssetBundle materialBundle = AssetBundle.LoadFromFile(GetBundlePathForLoadFromFile("material-bundle"));
    9.         AssetBundle cubeBundle = AssetBundle.LoadFromFile(GetBundlePathForLoadFromFile("cube-bundle"));
    10.         if (materialBundle == null)
    11.         {
    12.             Debug.LogError("Failed to load Material AssetBundle.");
    13.             return;
    14.         }
    15.         if (cubeBundle == null)
    16.         {
    17.             Debug.LogError("Failed to load Cube AssetBundle.");
    18.             return;
    19.         }
    20.  
    21.         GameObject prefab = cubeBundle.LoadAsset<GameObject>("MyCube");
    22.         Instantiate(prefab);
    23.  
    24.         cubeBundle.Unload(false);
    25.         materialBundle.Unload(false);
    26.     }
    27.  
    28.     public static string GetBundlePathForLoadFromFile(string relativePath)
    29.     {
    30.         #if UNITY_ANDROID && !UNITY_EDITOR
    31.         string streamingAssetsPath = Application.dataPath + "!assets/";
    32.         #else
    33.         string streamingAssetsPath = Application.streamingAssetsPath;
    34.         #endif
    35.         return Path.Combine(streamingAssetsPath, relativePath);
    36.     }
    37. }
    38.  
     
    Last edited: Aug 4, 2016
  17. rutz

    rutz

    Joined:
    Aug 21, 2013
    Posts:
    51
    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.
     
  18. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Hi rutz!
    Glad to hear it works. Also it should work without having #if UNITY_ANDROID block around now.
     
  19. rutz

    rutz

    Joined:
    Aug 21, 2013
    Posts:
    51
    Thanks @alexeyzakharov.
     
  20. dttngan91

    dttngan91

    Joined:
    Nov 21, 2013
    Posts:
    80
    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?
     
  21. surabhi18

    surabhi18

    Joined:
    Oct 7, 2016
    Posts:
    1
    Hi,

    I have used the same code with changes to asset bundle name and asset name. It works! But I am not able to set parent for the prefab. It does not update to the parent's position. Is there any solution?
     
  22. pahe

    pahe

    Joined:
    May 10, 2011
    Posts:
    543
    @dttngan91 What Unity version are you using? We use async loading too and although we experience performance losses when unpacking the assetbundles, we have no freezes. We're using 5.3.6p5 at the moment.
     
  23. Kalita2127

    Kalita2127

    Joined:
    Dec 6, 2014
    Posts:
    279
    Hi guys, I have a problem with retrieving json file from StreamingAssets. I still not try the code from @alexeyzakharov beacuse I'm not sure how to use them with json format file. I recently posted a question here.
    This is the code to communicate with json file :
    Code (CSharp):
    1.     using UnityEngine;
    2.     using System.Collections;
    3.     using LitJson;
    4.     using System.Collections.Generic;
    5.     using System.IO;
    6.    
    7.     public class ItemDatabase : MonoBehaviour {
    8.    
    9.         private List<Item> _database = new List<Item>();
    10.         private JsonData _itemData;
    11.    
    12.         void Start() {
    13.             Debug.Log(Application.streamingAssetsPath);
    14.             if(Application.isMobilePlatform){
    15.                 StartCoroutine("Mobile");
    16.             }
    17.             else if(Application.isEditor){
    18.                 if(File.Exists(Application.streamingAssetsPath + "/Items.json")){
    19.                     Debug.Log("Exists");
    20.                 }
    21.                 _itemData = JsonMapper.ToObject(File.ReadAllText(Application.streamingAssetsPath + "/Items.json"));
    22.             }
    23.             ConstructItemDatabase();
    24.         }
    25.    
    26.         IEnumerator Mobile() {
    27.             WWW loadDb = new WWW(Application.streamingAssetsPath + "/Items.json");
    28.             while(!loadDb.isDone){
    29.                 yield return loadDb;
    30.                 File.WriteAllBytes(Application.persistentDataPath + "/Items.json", loadDb.bytes);
    31.             }
    32.             _itemData = JsonMapper.ToObject(File.ReadAllText(Application.persistentDataPath + "/Items.json"));
    33.         }
    34.    
    35.         public Item FetchItemByID(int id) {
    36.             for(int i = 0; i < _database.Count; i++){
    37.                 if(_database[i].ID == id){
    38.                     return _database[i];
    39.                 }
    40.             }
    41.             return null;
    42.         }
    43.    
    44.         void ConstructItemDatabase() {
    45.             for(int i = 0; i < _itemData.Count; i++){
    46.                 _database.Add(new Item(
    47.                     (int)_itemData[i]["id"], _itemData[i]["title"].ToString(),
    48.                     (int)_itemData[i]["value"], _itemData[i]["description"].ToString(),
    49.                     (bool)_itemData[i]["stackable"], _itemData[i]["slug"].ToString()));
    50.             }
    51.         }
    52.     }
    53.    
    54.     public class Item {
    55.    
    56.         public int ID { get; set; }
    57.         public string Title { get; set; }
    58.         public int Value { get; set; }
    59.         public string Description { get; set; }
    60.         public bool Stackable { get; set; }
    61.         public string Slug { get; set; }
    62.    
    63.         public Item(int id, string title, int value, string description, bool stackable, string slug) {
    64.             this.ID = id;
    65.             this.Title = title;
    66.             this.Value = value;
    67.             this.Description = description;
    68.             this.Stackable = stackable;
    69.             this.Slug = slug;
    70.         }
    71.    
    72.         public Item() {
    73.             this.ID = -1;
    74.         }
    75.     }
    76.  
    Thanks guys. By the way I'm using Unity 5.3.2f1 Personal.
     
  24. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    @dttngan91, @pahe could you please provide more details on stalls and performance losses - we have perf tests running for AssetBundle.LoadFrom* methods and haven't seen any performance regressions.
     
  25. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    @Ali_Akbar_Montazeri please ensure "Items.json" file exists in the build and case is correct ("Items.json" vs "items.json"). Code you provided looks good for loading generic files from StreamingAssets folder.
     
  26. Kalita2127

    Kalita2127

    Joined:
    Dec 6, 2014
    Posts:
    279
    @alexeyzakharov the case is correct and it's already placed under StreamingAssets folder. Oh I forgot to mention that I build it for android
     
  27. Ginxx009

    Ginxx009

    Joined:
    Sep 11, 2016
    Posts:
    89
    Hello guys i'm having a problem a really big one because i cannot read this in mobile platform.

    #if UNITY_ANDROID
    string path = string.Format("{0}/datacenter.json", Application.streamingAssetsPath);
    Debug.Log("The path : " + path);

    if (File.Exists(path))
    {
    WWW reader = new WWW(path);
    try
    {
    CheckJSonManager.Instance._DataCenterJson = LitJson.JsonMapper.ToObject<DataCenterJson>(reader.text);
    DataCenter_BaseURL = CheckJSonManager.Instance._DataCenterJson.dataCenter;
    }
    catch(Exception ex)
    {
    Debug.Log("path :" + path + "\n" + ex);
    }
    }
    path = string.Format("{0}/dealerserver.json", Application.streamingAssetsPath);
    if (File.Exists(path))
    {
    WWW reader = new WWW(path);
    try
    {
    Debug.Log("************************* DealerServer.JSON *************************");
    CheckJSonManager.Instance._DealerServerJson = LitJson.JsonMapper.ToObject<DealerServerJson>(reader.text);
    }
    catch (Exception ex)
    {
    Debug.Log("Path : " + path + "\n" + ex);
    }
    } else
    {
    CheckJSonManager.Instance._DealerServerJson = new DealerServerJson();
    }
    // (Server list URL) 서버리스트 URL.
    // (Try for mobile version - PK 12/13/2017)
    // Changed the
    // serverListJsonURL = string.Format("{0}/pc_version/ph/check/serverList.json", DataCenter_BaseURL);
    // NOTICE_URL = string.Format("{0}/pc_version/ph/check/notice.json", DataCenter_BaseURL);
    //to
    serverListJsonURL = string.Format("{0}/mc_version/ph/check/serverList.json", DataCenter_BaseURL );
    NOTICE_URL = string.Format("{0}/mc_version/ph/check/notice.json", DataCenter_BaseURL);


    #elif UNITY_STANDALONE
    string path = string.Format("{0}/datacenter.json", Application.streamingAssetsPath);
    if (File.Exists(path)) {
    StreamReader reader = new StreamReader(path);
    try
    {
    CheckJSonManager.Instance._DataCenterJson = LitJson.JsonMapper.ToObject<DataCenterJson>(reader.ReadToEnd().Trim());
    DataCenter_BaseURL = CheckJSonManager.Instance._DataCenterJson.dataCenter;
    }
    catch (Exception ex)
    {
    Debug.LogError("path : " + path + "\n" + ex);
    }
    reader.Close();
    }


    // (Get dealer server connection information) 딜러서버 접속 정보를 가져온다.
    // (If the json file below is present, 'I am a dealer console) 아래 json파일이 존재하면, '나는 딜러콘솔이다'
    path = string.Format("{0}/dealerserver.json", Application.streamingAssetsPath);
    if (File.Exists(path))
    {
    StreamReader reader = new StreamReader(path);
    try
    {
    Debug.Log("********************* DealerServer.JSON ***************************");
    CheckJSonManager.Instance._DealerServerJson = LitJson.JsonMapper.ToObject<DealerServerJson>(reader.ReadToEnd().Trim());
    }
    catch (Exception ex)
    {
    Debug.LogError("path : " + path + "\n" + ex);
    }
    reader.Close();
    }
    else
    {
    CheckJSonManager.Instance._DealerServerJson = new DealerServerJson();
    }

    // (Server list URL) 서버리스트 URL.
    serverListJsonURL = string.Format("{0}/pc_version/ph/check/serverList.json", DataCenter_BaseURL);
    NOTICE_URL = string.Format("{0}/pc_version/ph/check/notice.json", DataCenter_BaseURL);
    #endif


    the problem here is that the serListJsonURL and NOTICE_URL couldn't get in the mobile platform :( anyhelp please.

    i'm getting it from aws s3 server like this

    https://********.amazonaws.com/pc_version/ph/check/serverList.json

    now when i tried it on mc_version it couldn't download the file :(