Search Unity

Why are there no synchronously LoadAsset APIs?

Discussion in 'Addressables' started by zhuxianzhi, Jul 11, 2018.

  1. zhuxianzhi

    zhuxianzhi

    Joined:
    Mar 30, 2015
    Posts:
    17
    Another question, what if the resource does not call Addressables.ReleaseAsset?
     
  2. taylank

    taylank

    Joined:
    Nov 3, 2012
    Posts:
    73
    My understanding is that the system needs to work equally well with remote and local assets. If they did a synchronous load on a remote asset, it could be a noticeable performance issue depending on how long it takes to load. I'm not sure why there is no synchronous load for assets that are placed in a local group, though.
     
  3. PaulBurslem

    PaulBurslem

    Unity Technologies

    Joined:
    Oct 7, 2016
    Posts:
    44
    Correct - this was a design decision to allow for a seamless transition when moving your assets from a local location (Resource folder, StreamingAssets, etc) to a remote location without having to change code. The returned IAsyncOperation is yieldable so you can use it in coroutines.
     
    RecursiveFrog and karl_jones like this.
  4. zhuxianzhi

    zhuxianzhi

    Joined:
    Mar 30, 2015
    Posts:
    17
    Not all projects need to load remote assets, there is no synchronous LoadAsset API, and you can't quickly replace the original asset loading system (Resources API)
     
    nepoez likes this.
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    3,870
    If you really need the asset to be finished loading before you continue the main thread, I guess you could just do a
    while(!loading.isDone);
    on the IAsyncOperation. That can also be extracted into a helper method pretty easily.
     
    RecursiveFrog likes this.
  6. Kastenfrosch2

    Kastenfrosch2

    Joined:
    Mar 19, 2017
    Posts:
    4
    @Baste
    Code (CSharp):
    1. ResourceManagement.IAsyncOperation<GameObject> loading = Addressables.LoadAsset<GameObject>("Foo");
    2. while (!loading.IsDone) {}
    3.  
    Unfortunately the loop never finishs when being called from the Main Thread.
    I guess resource loading is ticked from within the MainThread itself :(.
     
  7. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    356
  8. Kastenfrosch2

    Kastenfrosch2

    Joined:
    Mar 19, 2017
    Posts:
    4
    @MNNoxMortem The problem with this approach is, that it's not really sync. So I cannot guarantee that after I called my Load() function, I can immediately acces the loaded object in the code line afterwards.
    That takes away some simplicity of the old Resources.Load() approach.
     
    nepoez and MNNoxMortem like this.
  9. jayatubi

    jayatubi

    Joined:
    Dec 9, 2013
    Posts:
    63
    Some third party library need synchronous IO interfaces for example the lua script integration. To implement the lua `require` function the program should return content of the requried script immediately. The lua vm was written in c which is not yieldable thus the asynchronous IO can't work for it. For now we have preload all the lua scripts into memory on the startup.
     
    zyc_dc likes this.
  10. zyc_dc

    zyc_dc

    Joined:
    May 11, 2018
    Posts:
    26
    Yeah. I also have the problem when using Lua. We really need sync load.
     
  11. gsantosgeneragames

    gsantosgeneragames

    Joined:
    Nov 21, 2018
    Posts:
    7
    +1 to the synch load
     
  12. nepoez

    nepoez

    Joined:
    Sep 11, 2011
    Posts:
    293
    Yes we need sync load. It's a real pain for an existing large project that relies heavily on sync load to convert to the new system :(
     
  13. Kirsche

    Kirsche

    Joined:
    Apr 14, 2015
    Posts:
    36
    Synchronous API is also needed if you want to create GUI programmatically like this:

    Code (CSharp):
    1.  
    2. private void CreateGUI()
    3. {
    4.     Window window = new Window("Options");
    5.     window.SetSize(400, 300);
    6.     window.SetAlignment(HAlign.Left, VAlign.Top);
    7.     window.SetPosition(50, 250);
    8.  
    9.     Panel panel = new Panel(window);
    10.     panel.SetBackgroundColor(255, 0, 0, 155);
    11.     panel.SetStretch(true, true);
    12.  
    13.     TabPanel tabpanel = new TabPanel(panel);
    14.     tabpanel.SetStretch(true, true);
    15.  
    16.     var tab = tabpanel.AddTab("Graphics");
    17.     var list = tab.AddComponent<VerticalLayoutGroup>();
    18.     list.childForceExpandHeight = false;
    19.     list.spacing = 5;
    20.  
    21.     // ...
    22. }
     
  14. unity_bill

    unity_bill

    Unity Technologies

    Joined:
    Apr 11, 2017
    Posts:
    581
    Is that an editor window? or are you making a GUI window inside your game's runtime?

    Though it's on the list, Addressables currently can't be utilized at edit time.
     
    5argon and MNNoxMortem like this.
  15. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,191
    Glad it is on the list! It is crucial when unit tests ran into them and I hate having to do if Application.isPlayMode then switch to AssetDatabase on all Addressables so that they are unit-test compatible.
     
    MNNoxMortem and Deleted User like this.
  16. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    356
    (@unity_bill,) @5argon also just ran into this problem. Did you find any suitable workaround to write unit tests when Addressables are involved? How do you map addressable keys to AssetDatabase path? I assume you just don't and write all tests directly using AssetDatabase.
    Code (CSharp):
    1. Addressables are not available in edit mode
     
  17. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,191
    I didn't map, I just provide 2 separate paths manually... There should be a way to ask the catalog for the mapping to AssetDatabase compatible path but I remembered catalog doesn't build immediately (and that's why AAS is not edit mode compatible in the first place) and things may change for the upcoming v1.0.

    Code (CSharp):
    1. public static class AddressablesExtension
    2. {
    3.     public static bool IsNullOrEmpty(this AssetReference aref)
    4.     {
    5.         return aref == null || aref.RuntimeKey == Hash128.Parse("");
    6.     }
    7.  
    8.     /// <summary>
    9.     /// Use the Addressables system if in real play, use `editorAsset` if in edit mode.
    10.     /// </summary>
    11.     public static async UniTask<T> LoadAssetX<T>(this AssetReference aref)
    12.     where T : UnityEngine.Object
    13.     {
    14. #if UNITY_EDITOR
    15.         if (!Application.isPlaying)
    16.         {
    17.             return (T)aref.editorAsset;
    18.         }
    19. #endif
    20.         var op = aref.LoadAsset<T>();
    21.         var result = await op;
    22.         //Debug.Log($"{op.Status} {object.ReferenceEquals(null, op.Result)} {op.IsDone} {op.IsValid} {op.OperationException}");
    23.         return result;
    24.     }
    25.  
    26.     /// <summary>
    27.     /// Use the Addressables system if in real play, use `AssetDatabase` if in edit mode.
    28.     /// </summary>
    29.     /// <param name="key">Addressable key</param>
    30.     /// <param name="pathForEditor">This starts with "Assets/..." and you need the file extension as well.</param>
    31.     public static async UniTask<T> LoadAssetX<T>(string key, string pathForEditor)
    32.     where T : UnityEngine.Object
    33.     {
    34. #if UNITY_EDITOR
    35.         if (!Application.isPlaying)
    36.         {
    37.             return AssetDatabase.LoadAssetAtPath<T>(pathForEditor);
    38.         }
    39. #endif
    40.         return await Addressables.LoadAsset<T>(key);
    41.     }
    42. }
    The better way is probably we have to ask the addressable config scriptable object file for the current mapping.
     
    MNNoxMortem likes this.
  18. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    5,618
    So once again, because of Unity's obsession with remote loading stuff, this is still not a proper replacement for the Resources folder. Exactly like the Asset Bundles before it.

    Cool.

    I look forward to a new solution in a few years, that will replace this one, that will also fail to replace the Resources folder for a 3rd time.
     
    kraihd likes this.
  19. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,191
    That's exactly right, since the provider for the bundle is calling AssetBundle.LoadFromFileAsync inside. (UnityWebRequestAssetBundle.GetAssetBundle in the case of remote) And each group is essentially an asset bundle. It is not an entirely new architecture.

    If you want synchronous function asap without waiting a few years, maybe it is faster to hack up your own provider based on AssetBundleProvider.cs that uses AssetBundle.LoadFromFile instead + assign null request operation + call complete immediately. (try to do it like the "invalid path" case in that file may work?) Make it so that the IAsyncOperation's .Result is immediately available after the LoadAsset line and go by this assumption when you code it.

    (This assumption would look a bit ugly as you don't know at glance which IAsync is immediately done and holding result or not, being coming from the same Addressables.LoadAsset that take account of async load. Otherwise you would now have to hack up an another Addessables.LoadAssetSync which returns the result or null. I think I can feel why UT didn't go this way.)

    But I can imagine that it would not work if you have dependencies since IAO would ask and wait for those deps in chain and make your .Result still null even with synchronous load.

    *Edit : I tried, but I forgot the first step of all the catalog .json file loading is also part of the dependency chain. (Providers are : JsonAssetProvider and ContentCatalogProvider) You will have to hack those into synchronous as well. However, the place where we could interchange those two are not exposed to be easily changable like AssetBundleProvider and BundledAssetProvider (which you can see the drop down on the group). You will have to go great length to make it work. (Json catalog loading is also taking in account in the case that catalog is online). At this point I think it is not worth it to go against the flow of API. Async hassle is for the best of ubiquitous use.

    *Also the AAS docs should edit out the part where it says migration from Resource.Load is as easy as string replace. That gave me false hope even though now I have conformed to the async way.
     
    Last edited: Mar 3, 2019
    kraihd, MNNoxMortem and AcidArrow like this.
  20. AcidArrow

    AcidArrow

    Joined:
    May 20, 2010
    Posts:
    5,618
    Thanks for the reply, but I’m just going to keep using the Resources folder until Unity removes the functionality.

    (or releases something to replace it, which they haven’t and aren’t planning to from what I can tell)