Search Unity

Resource.LoadAllAsync - where is it?

Discussion in 'Scripting' started by laurentlavigne, Dec 6, 2016.

  1. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    We have LoadAsync, cool, now LoadAll definitely takes longer so async on this one would make sense yah?
    So where is it.
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
  3. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Bundles require to export them to external files and you need a bunch of boilerplate code to handle them in editor, right?
     
  4. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,203
    MMX3VIII, laurentlavigne and Kiwasi like this.
  5. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    read the post - LoadALLAsync
     
  6. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,203
    You're asking for it to load the entire resources folder, correct? It clearly states it does that if you pass an empty string.
     
    laurentlavigne and Kiwasi like this.
  7. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Lol. When in doubt, read the manual. Can't believe I missed that.
     
  8. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    ResourceRequest.asset returns only one object no?
     
  9. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I imagine you'd cast it to an Object[].
     
  10. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Why not try it and see? You could answer that more accurately and faster by simply opening Unity.
     
  11. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    I didn't know you could cast an Object to an Object[] so I tried () and "as" and nope it doesn't compile.
    So I did my own soup casting the result to IEnumerable and building the list.
    .asset is null, what am I doing wrong?

    Here is the code.
    Code (CSharp):
    1.     public List<GameObject> objects = new List<GameObject>();
    2.     IEnumerator Start () {
    3.         var timer = Time.time;
    4.         var resourceLoad = Resources.LoadAsync ("", typeof(GameObject));
    5.         yield return resourceLoad;
    6.         Debug.Log (Time.time-timer);
    7.         if (resourceLoad.asset.GetType ().IsArray) {
    8.             var objs = (IEnumerable)resourceLoad.asset;
    9.             foreach (var o in objs)
    10.                 objects.Add ((GameObject)o);
    11.         }
    12.     }
     
  12. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,364
    Got a reply from Unity QA it's a bug and sent for resolution. Let's see if resolution turns out to be removing the bit in the documentation ;)
    bug# 858737
     
  13. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Ladace likes this.
  14. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    Here is the corresponding bug-report:
    https://issuetracker.unity3d.com/is...load-all-gameobjects-from-the-resource-folder

    If you need "LoadAll" functionality, you could build a table that contains asset paths of all resources at build time and then use this information to load and look-up assets at runtime.

    That being said, Unity Technologies recommends to avoid the Resources system.
    https://unity3d.com/learn/tutorials/topics/best-practices/resources-folder
     
    Prodigga likes this.
  15. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Your Google Fu is on point. Cheers.
     
    Peter77 likes this.
  16. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    725
    It's nice and all the whole idea "avoid the resources system" but it's mighty convenient, and it seems like the best bet when working with Android and especially WebGL. I'm struggling with this and the idea I had was the same as mentioned, just somehow have a list of the relative resource paths. It's taking a while to crack the puzzle, though.

    Using WebGL by the way you're also limited in where you can't hang the browser with while { !isDone }; as well...
     
  17. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    725
    There IS a solution if you want to do things like preload assets from Resources at your scene's start.

    Basically, you can write a TextAsset to a folder called 'Paths' (or whatever you'd like) in your resources folder upon the import of your asset like so...this example uses audio. This is an editor script that's placed into an 'Editor' folder:

    Code (CSharp):
    1.  
    2. public class MyAudioPostprocessor : AssetPostprocessor
    3. {
    4.     private string GetFileDirectoryForResources(string inputString)
    5.     {
    6.         inputString = inputString.Replace("\\", "/");
    7.         string outputString = inputString.Substring(inputString.IndexOf("Resources/") + 10);
    8.  
    9.         return outputString;
    10.  
    11.     }
    12.  
    13.     void OnPreprocessAudio()
    14.     {
    15.         AudioImporter audioImporter                                 = (AudioImporter)assetImporter;
    16.         AudioImporterSampleSettings audioImporterSampleSettings     = audioImporter.defaultSampleSettings;
    17.         audioImporterSampleSettings.loadType                        = AudioClipLoadType.DecompressOnLoad;
    18.         audioImporter.defaultSampleSettings                         = audioImporterSampleSettings;
    19.  
    20.         string filePath                 = audioImporter.assetPath;
    21.         string fileNameNoExtension      = Path.GetFileNameWithoutExtension(filePath);
    22.         string fileDirectory            = Path.GetDirectoryName(filePath);
    23.         string fullPathNoExtension      = fileDirectory + "\\" + fileNameNoExtension;
    24.  
    25.         string fileDirectoryToWriteIntoFile = GetFileDirectoryForResources(fileDirectory + "/" + fileNameNoExtension);
    26.  
    27.         File.WriteAllText(Application.dataPath + "/Global/Resources/Paths/" + fileNameNoExtension + ".txt", fileDirectoryToWriteIntoFile);
    28.  
    29.     }
    30.  
    31. }
    32.  
    Then what you do is when you preload the asset, in my case audio, you would load the text asset once you have the audio clip's name you want to load, use textAsset.text to get the path and then use that the load the actual audio clip. This is so that then you can play audio files wherever you want, in any subfolder etc... and it'll find it.

    Code (CSharp):
    1. TextAsset pathTextAsset = Resources.Load<TextAsset>("Paths/" + AudioClipToLoadName + "_Path");
    2.             string audioPath              = pathTextAsset.text;
    3.             AudioClip audioClip         = Resources.Load<AudioClip>(audioPath);
    4.  
    5.             preloadedAudioClips.Add(audioClip);
    6.  
    That way you avoid uses LoadAll at all. The only thing that would make LoadAll useful would be Async, but there are ways around it.

    I think this is a good solution if you're making a simple WebGL game and want to load audio that's gonna be packed up inside your built game. The only thing you then have to focus on externally is save/load files.
     
    CunningFox146 likes this.
  18. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    Wouldn't it be way simpler if you either:
    1) Add a MonoBehaviour to a gameobject in your scene that has an array of AudioClip's and serves of some kind of audioclip database.
    2) Add a reference to the AudioClip in the MonoBehaviour where you want to play it.
     
    Prodigga likes this.
  19. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    725
    @Peter77 The game object would just have to be global and hold audioclips, then when a scene loads in it's preloading process it needs to detect in your events in your scene where a PlayBGM would happen or whatever your event is called and preload that clip, then unload the clips when the scene transfers into the next one...unless you're just streaming the clips. It would be like a scene manager - > audio manager that would have that array or list of audio clips I guess, then maybe make some methods like PreloadClip() UnloadAll() and all that. I don't know if there's an easier way than that.
     
  20. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,619
    If there is a reference to an AudioClip in a scene, Unity loads the clip automatically, unless you disable the "Preload Audio Data" option on the clip:
    https://docs.unity3d.com/Manual/class-AudioClip.html

    If you switch to another scene, Unity unloads the AudioClip when no longer used.

    There shouln't be any need for a global manager if you just want to have that basic preload/unload built-in functionality.
     
  21. astracat111

    astracat111

    Joined:
    Sep 21, 2016
    Posts:
    725
    @Peter77 Huh...that's interesting, I hadn't looked into that. I guess I just have the tendency to want to do everything manually in a way to feel like I've got more control over everything.

    What I was doing was just building a list of audioclips called 'scene_audioclips' and then unloading each clip before the scene changes manually.

    About sound and scenes shifting, I might know what you mean...when playing an SFX when the scene changes I notice that on a scene change the SFX stops completely even though it's a PlayOneShot().

    In any case, as it pertains to implementation in a game, I feel like the question by the OP has to include scene management. I don't really know if you can remove the two.
     
    Last edited: Jun 2, 2019
  22. Wappenull

    Wappenull

    Joined:
    Oct 29, 2013
    Posts:
    51
    Pardon to unearth this necro.
    Here is message left for future internet traveler.
    FYI: this post comes up early on Google term "unity resources.loadall async"

    If you are looking to improve stall time for
    Resources.LoadAll
    Here is workaround.

    • Call the same set of Resources.LoadAll on some loading screen (that permit stall) before actual call (where you don't want it to stall too long)
    • Could separate Resources.LoadAll into several chunk of directories and call it with coroutine over several frames. such as
      Resources.LoadAll( "path1" ); yield; Resources.LoadAll( "path2" );

    The reason behind this:
    See C# reference for internal code of Resources API.
    If you look closely at
    ResourceRequest
    (the thing returned by
    LoadAsync
    API) accessing 'asset' will query to the same
    Resources.Load
    surprisingly.
    That's mean Resources has internal caching on C++ side, if you just load it beforehand, no matter by which method, be the normal way or async way. The resource will already be there, so next resource request will complete faster.

    Unless you used UnloadUnusedAssets or UnloadAsset

    Of course you could also use Addressable system
    To get the nice async benefit. But it is not trivial switch, depends on your stage of project. I have to mention this anyway.

    An unrelated and nothing-personal note to OP:
    Should be more polite when seeking help from public.
     
    imPrgrmr and gagasik like this.
  23. Feelnside

    Feelnside

    Joined:
    Sep 30, 2016
    Posts:
    83
    I tried to use Addressable. Conclusion:
    1) Sometimes you can forgot to rebuild addressable data for the particular platform (iOS, Android), as result you are building the game, pushing it on device and see that you need to go back and rebuild the project from scratch because of non-updated addressable assets.
    2) A lot of rework of the code base (Resources much more simpler to use)
    3) Addressabe build 142 mb download data. Resources build 126 mb download data. My Addressable didn't had any issues in the analysis tool but anyway simple resource build has much more less data at the end (pics below)
    4) The only one profit - smooth async upload.
    5) As result no reason to use Addressables at all.
     

    Attached Files:

    Wappenull likes this.
  24. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,933
    Feel like this is overlooking one big benefit of addressables: You can assign them in the inspector. With resources you are filling your code with strings. If your game is already built on Resources, changing your code around is no doubt difficult, but if you start with Addressables it's easier in the long run as your code becomes more reusable.

    The first issue you listed can be just be fixed by getting in the habit of it. Ask yourself, have I adjusted content that's in my addressables? If so, let's build that first.

    Yes Resources is going to be a smaller file size, because everything gets lumped into a single serialized file. This is also why it's slow to load from as well.

    If you're making mobile games, I feel like you're doing yourself a disservice by not using it, particularly in an environment when memory management is more critical. Not to mention the time it adds to start up.

    And yes I realise this is a necro-ed thread.
     
    Wappenull likes this.