Search Unity

Make WWW request to local asset bundle BLOCK main thread until file loaded

Discussion in 'Editor & General Support' started by zalogic, Jul 22, 2011.

  1. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Hi guys,

    Is there anyone in this forum who needed to make a WWW request to load a local asset bundle (or more) but
    block the main thread until it's finished loading the asset bundle?

    The reasons:
    1) The ONLY way to load an asset bundle is by using a WWW request with the "file://" protocol.
    2) There are times when you need to replace a Resources.Load(...) system with an asset bundle loading system (using WWW) and because there might be situations where Resources.Load(...) has been used in a lot of static methods, I can't yield the WWW request in a static method.
    3) If you use local asset bundles as resources you obviously need to have a blocking load method like Resources.Load(...) so you can use it even in static methods.

    This has been driving me nuts for a week now. Did anyone ever needed something like this and found a solution? :(
     
  2. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Then just block it, thats trivial.

    make a

    While (!www.done)*{}

    loop and it will block as it runs in the main thread and blocks the thread into this loop until the download has taken place

    but even then it won't be blocking completely and the whole point of asset bundles IS to not be blocking.
    Yeah if you want to use them as resource replacements ... but why not use Resources at all and just do it all async? why try to force the better to be worse than the worse to be replaced with the better ;)
     
  3. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Yeeeeeeeeeees!!!!!!!!! Dreamora !!! I've been praying for an answer from you my friend!!!!! :)

    First THANK YOU for answering so fast my friend!
    Secondly, I can't use Resources.Load(...) because the asset bundles have been downloaded from a server when the application first starts (like an installer) and I needed to replace a bunch of Resources.Load(...) calls with something similar to load the asset bundles instead.

    I tried "while(!www.isDone){ }" and it freezes the editor permanently :(. I didn't try it on the iPhone or Android yet, but I will right now. In the editor it freezes permanently. It's like it doesn't ever finish the request.
     
  4. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Well the editor is a special case cause the editor force syncronizes threads and coroutines and alike, thats why some of the ugliest and hardest to track bugs never ever even show up.

    but yeah might fail there too.

    With Unity 3.4 you are going to want to use the currently only webplayer available Cache.LoadFromCacheOrDownload I guess and handle it that way.

    as for the installer that downloads: well not on iOS cause apple will just reject you if your app does not offer a meaningfull functionality without going online additionally. but yeah if you try to update assets later on the problem naturally still exists.

    Question though is: why do you use resource at all? why not have them all in asset bundles right from the start. nothing prevents you transfering the asset bundle along the install, StreamingAssets folder is there for such stuff :) (see movie documentation for mobile if you never heard of it)
     
  5. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Dreamora, my friend! If you EVER drop by Romania give me a PM buddy because I AM your biggest FAN around here and it will be my pleasure to drink a beer with you. ;)

    Didn't know about the iPhone reject case. Thank you for pointing that out. I guess I will use this (if it works) only on the Android.
    I am testing the main thread block on the device as we speak and get back to you in a few minutes.
     
    Last edited: Jul 22, 2011
  6. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    while(!www.isDone) { } doesn't work on the iPhone. I don't think it will work on the Android either. :(

    It freezes the app and it only displays the last Debug.Log I've placed before the WWW request. :(
    It never returns. :( I don't understand why, because WWW does execute on a separate thread. Unless a deadlock happens if the WWW thread is trying to access the main thread to write the result into "isDone" and if the main thread is blocked...hmmm...I wonder
     
  7. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Sorry, I am so mixed up here that I forgot to answer your question. I used Resources.Load() first because I didn't thought I will need an installer for Android. The app got so big (around 150 MB) and then I found out about Android download limit on some devices.
    I need the installer only for Android and the quickest way to modify the actual code was to download a bunch of required asset bundles from a server when the app first starts and load them in a similar way like Resources.Load().

    But if I can't load an asset bundle while blocking the main thread until the bundle loads I am without solution to this problem. :(
    I am sure other people would need something like this someday. :(
     
  8. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    That or the main thread actually is bound to the process preventing WWW from terminating the load at all
     
  9. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Oh my God. :( I'm dead.
    Isn't there another way to load an asset bundle previously downloaded from a server?
    Is there any solution to my stupidity ? :(
     
  10. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    There will be one but you will have to wait till 3.4 before I can tell you more about it I fear, but ping me then. (though it won't act as resource.load replacement either but you might want to favor it then over WWW or using of resources potentially)
     
  11. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Thank you for your time dreamora. I appreciate it.
    Any estimate on the release date for Unity 3.4? Any rumors? :(

    As long as it will block the main thread until it loads the asset bundle it will just fine.

    Because there are many situations where you might have in a static method something like this:
    line 1: wait for resource to load
    line 2: create and setup game object with above loaded resource
    line 3: initialize other stuff related to the above loaded resource

    And you must wait for that resource (at line 1) to load somehow in a static method.
     
  12. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    If there are they are kept more secret than apples upcoming things ;)

    It won't and there never might be anything for that. The future is streaming and asyncronity, not permastutter from hell as Resource.Load causes it. I would consider it more likely that Resources.Load end to be blocking.

    Nope you must not.

    1. Fire off the asset bundle load and wait for it to finish (possible with WWW cause it will not be done until the asset bundle is ready for consumption)

    2. Once loaded either fire of an Instantiate with the mainAsset if you really want it to block (yes that part blocks ;)) or use the assetBundle.LoadAsync function to not have it blocking.

    3. Have a object in the asset bundle that sets a corresponding flag on the static manager so it can fire of the rest related to it (or better for your own favor, making it a LinkedList where the prefab adds itself to so the manager can handle more than 1 assat bundle in parallel)
    Unless you use instantiate then you can check it from the manager that fired of the WWW

    the only reason it does not work for you is cause you are not willing to adapt your code to how asset bundles and async / streaming work, its less a problem of resources vs asset bundles it seems just from that "3 line list". I know async can be hard to wrap the head around but I would highly recommend to do it now while unitys support on that end is still years behind current and thus very limited and focused. if you grasp the concepts now, you don't need to do it later, if you try it later you will at worst be swamped with "too many things at once"
     
  13. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    Dreamora my friend. One last attempt at this problem. :)
    From multiple tests and from what you said earlier:
    I concluded that you are right. The editor does force synchronize threads.
    In the editor if I have some code like this:
    line 1: WWW www = new WWW("file://" + localUrl);
    line 2: Debug.Log("Finished loading: " + www.bytes.Length());
    line 3: AssetBundle loadedBundle = www.assetBundle;
    ...

    I noticed that in the editor the WWW request halts the main thread execution ONLY for the "file://" protocol until it finishes loading the entire asset bundle.
    So I was thinking if there is ANY possibility to also do a force synchronize on the WWW loader at run-time like the editor does...somehow... :-S (unless the editor is doing this synchronize by
    accessing some internal stuff in which case this solution is shot to hell).

    Maybe by getting the main thread Dispatcher and do the WWW request using the Dispatcher and somehow... I'm lost :(

    Do you see any light on this idea? Or I'm just going crazy. :(
     
    Last edited: Jul 22, 2011
  14. zalogic

    zalogic

    Joined:
    Oct 6, 2010
    Posts:
    273
    I would like to return with a conclusion to the above experiment of blocking the main thread to wait for a WWW request to finish:
    it's not possible.
    Just in case someone else is trying something like this for any reason. Like dreamora said: it's not the future of how things should be implemented.