Search Unity

Question Resources.load only working in editor

Discussion in 'Scripting' started by AnahidE5, May 16, 2022.

  1. AnahidE5

    AnahidE5

    Joined:
    Jan 10, 2022
    Posts:
    40
    So I've seen posts related to this but I didn't find out why it happens or how to fix it. I'm creating a VR app and I'm using Resources.load for some sprites. To be fair, I have used this exact method in another app that I made for mobile devices and everything works fine there. But basically, when I'm testing my vr app in the editor, pictures are loaded. But not after I build it on the headset. Is there any size limit on how much we can put in Resources folder? Thanks.

    I would include more of the code if it was necessary but it works in editor so i don't think i have a code issue.
    Code (CSharp):
    1. theImagePlaceHolderMR.sprite = Resources.Load<Sprite>(fileName);
     
    Last edited: May 16, 2022
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    The point of Resources.Load<T>() is that it always works, assuming you meet all the requirements.

    The next thing is to find out what that "fileName" is in the running app, and also to find out if the above code is even executed.

    You must find a way to get the information you need in order to reason about what the problem is.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494
     
    AnahidE5 likes this.
  3. AnahidE5

    AnahidE5

    Joined:
    Jan 10, 2022
    Posts:
    40
    Thank you Kurt, like always. Fair enough. I did more testing (can be seen in the messy code). Should have realized (System.IO.Directory.EnumerateFiles("Assets/Resources/" + path).Count())/2; isn't going to work after build.

    Code (CSharp):
    1.  
    2. public void UpdateImageCT()
    3.     {
    4.  
    5.         // string fileName = "Medical images/1.1 P20/CT/Bone/CT Bone (2)";
    6.         // theImagePlaceHolderCT.sprite = Resources.Load<Sprite>(fileName);
    7.         // Debug.Log(fileName);
    8.         // TMPReport.text = fileName;
    9.  
    10.         // vrUISliderCT = GetComponent<Slider>();
    11.         TMPReport.text = "Update CT image called";
    12.         string pNModel = transform.parent.parent.GetComponent<MedicalImageViewerDataHolder>().patientNModel;
    13.         // string imgType = transform.name.Replace("Slider", "");
    14.         string imgType = "CT";
    15.         TMPReport.text = "2";
    16.         path = "Medical images/" + pNModel + "/" + imgType + "/" + CTseries;
    17.         Debug.Log("Path is: " + path);
    18.         int count = (System.IO.Directory.EnumerateFiles("Assets/Resources/" + path).Count())/2;
    19.         Debug.Log("Count is: " + count);
    20.         TMPReport.text = "3";
    21.         // TMPReport.text = transform.parent.parent.name;
    22.         vrUISliderCT.maxValue = count;
    23.         vrUISliderCT.minValue = 1;
    24.         TMPReport.text = "4";
    25.  
    26.         theImagePlaceHolderCT.sprite = null;    
    27.         TMPReport.text = "5";    
    28.  
    29.         if(theImagePlaceHolderCT.gameObject.activeSelf)
    30.         {
    31.             TMPReport.text = "6";
    32.             // vrUISlider = GetComponent<Slider>();
    33.             i = (int)vrUISliderCT.value;
    34.             // i = 1;
    35.             string fileName = path +"/CT " + CTseries.Replace("Series ", "") + " (" + i.ToString() + ")";
    36.             TMPReport.text = "7";
    37.             // TMP.text = fileName;
    38.             Debug.Log("File name is: " + fileName);
    39.             theImagePlaceHolderCT.sprite = Resources.Load<Sprite>(fileName);
    40.             TMPReport.text = fileName;
    41.         }
    42.     }
    43.  
     
    Kurt-Dekker likes this.
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    Wow, yeah, that wouldn't make anyone down in the Resources.Load<T>() boiler room happy. :)

    Unfortunately there's no way (that I know of) to enumerate what you do have.

    You can trivially make an editor script to create a text file directory at build time (or under tool control), basically a manifest of what could possibly be Resource.Load-ed
     
  5. AnahidE5

    AnahidE5

    Joined:
    Jan 10, 2022
    Posts:
    40
    is it a bad idea to do something like this:
    Code (CSharp):
    1. public static int TotalImgCount(string path)
    2.     {
    3.         UnityEngine.Object[] imgs = Resources.LoadAll(path);
    4.         totalImgCount = imgs.Length;
    5.         Resources.UnloadUnusedAssets();
    6.         return totalImgCount;
    7.     }
    And then call it instead of enumerateFiles..?
    I mean even unloading I don't think is necessary since this is an image viewer with a slider so if I want to activate the viewer, I need the images to be loaded.

    hey I just wanted to say, every now and then I read help-wanted posts but I can never help them. But once I can, I promise i'll give as much (hopefully more) help as you've given me to others!
     
    Kurt-Dekker likes this.
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    Just understand that it WILL try to load all the objects from that path at the same time and it WILL require the maximum amount of memory. This may or may not matter in your context.

    Also, never use Resources.LoadAll() unless you just want a blob of everything: images, text files, meshes, anything it can find in that directory.

    Always use
    Resources.Load<T>()
    , never use
    Resources.Load() as T


    https://forum.unity.com/threads/resources-load-not-working.1137463/#post-7306567

    And the same goes for
    Resources.LoadAll<T>()
     
    AnahidE5 likes this.
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,990
    I once made the ResourceDB over here that did exactly that. It creates a ScriptableObject and stores all resources files (and even folder information) in a linear list of resource items so this metadata is available at runtime. Though I have to say I haven't looked at this code for ages, so I can't tell if it still works ^^.
     
    Kurt-Dekker likes this.
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,689
    That's pretty spiffy. If I read it correctly, it isn't storing actual references to the items, just their names for use in the Load<T>() method... am I seeing that right? I like the overall design.

    ResourceDB smells like a far more useful version of my poor-man's
    GameObjectCollection
    thingy, which I use everywhere, but it's just a list-o-stuff: load it and you get EVERYTHING.

    https://gist.github.com/kurtdekker/68b3fd9d4202888b4afc17b32eed6790

    I think I shall throw a link to your above article into the comments for GOC.
     
  9. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,990
    Exactly. The main point was that resources that are not referenced can actually be unloaded / doesn't need to be loaded by Unity. So we can avoid things like LoadAll because some people had like 5k+ assets and loading them all would be a bad idea.

    It actually stores the file and folder names inside all resources folders and some other metadata like the file extension and the actual type of the asset.

    The linear list of resource items was a workaround to avoid the usual nesting issues when it comes to serialization. However since we have now SerializeReference this could be simplified as we could store the actual hierarchy directly since Unity itself does a similar thing behind the scenes.
     
    Kurt-Dekker likes this.