• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by Fattie · Jan 25, 2016 at 03:56 PM · assetspaths

Recover path information for an asset, but at runtime...

Say you have a folder Resources/Stuff

In "Stuff" you have 100s of folders each with many small assets.

You do a LoadAll on "Stuff" -- everyt$$anonymous$$ng works perfectly.

However for each of the small assets ... it would be great to know the NAME OF THE FOLDER w$$anonymous$$ch was the parent of that asset.

Is there any way at all to do t$$anonymous$$s?

I don't mind if it is in Resources, or a normally-loaded folder.

In short, for some asset X, it would be great to know the name of the parent folder, at run time, for organisational reasons.

It seems hard to believe there is not a way to do t$$anonymous$$s...

is it a fact that you ABSOLUTELY CAN NOT recover path information at runtime?

cheers...

Comment
Bunny83
Dave-Carlile
RobertWebb
Thorny2000
karlthepagan
Vedran_M

People who like this

6 Show 0
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by Bunny83 · Jan 25, 2016 at 04:33 PM

Yes, it seems there is no way to "query" anyt$$anonymous$$ng from that "virtual folder structure" that the Resources folders build up. Once an object is loaded from the resources folder, it has no relation to where it came from. So for example loading a Texture2D asset from a Resources folder just gives you a Texture2D object, just like "new Texture2D()" would with the exception that "new Texture2D()" gives you a new, empty image.

See t$$anonymous$$s post for a possible solution.

edit

I just created a general purpose ResourceDB script w$$anonymous$$ch should close the gap. I created two files:

  • ResourceDB.cs (download)

  • ResourceDBEditor.cs (download)

The "ResourceDB" script is just a normal runtime script, so place it anywhere in your project. The "ResourceDBEditor" script, as the name suggests, is an editor script and therefore has to be placed in a folder called "editor". The ResourceDBEditor isn't needed, but it allows easier access to some features and protects the saved data from accidental changes.

What the script does:

T$$anonymous$$s script is a scriptableobject w$$anonymous$$ch is ment to be stored as asset into a resources folder. It adds a menu item to Unity under "Tools" w$$anonymous$$ch allows you to create / update the resource database file. It's automatically created under Assets/Resources/ResourceDB.asset. If you select that file in Unity it should show the custom inspector for t$$anonymous$$s class. There you can see what information is actually stored and it allows you to initiate a manual update or enable automatic updating. When automatic updating is enabled, the integrated AssetPostprocessor will check all assets w$$anonymous$$ch got modified (added, moved, deleted) and if they belong to a resourced folder, the postprocessor will trigger an update.

T$$anonymous$$s script will store the following information for each file inside resources folders:

  • The relative path to that asset. T$$anonymous$$s is the same path that is needed in Resources.Load.

  • The filename without extension. Again that is needed when you want to use Resources.Load.

  • It stores the extension seperately. The extension isn't used for anyt$$anonymous$$ng, it's just there if you need that information.

  • It also stores the actual assettype. T$$anonymous$$s is done when the database is updated. It stores the System.Type assembly qualified name of the type. For example t$$anonymous$$s is the type string for the Material class: UnityEngine.Material, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null. From t$$anonymous$$s string we can reconstruct the actual System.Type object.

Initially i thought about storing the exact file structure of the resources folders in a custom class $$anonymous$$erarchy. However since Unity has a max nesting level of 7 it would limit the user to 7 nested subfolders inside a resources folder. Even almost nobody will reach t$$anonymous$$s depth i like it as robust as possible. That's why all file information is stored in a flat "master file table" (just like NTFS works). I still rebuild the $$anonymous$$erarchy structure at runtime for easier usage.

The ResourceDB uses a custom class called "ResourceItem". A ResourceItem can represent both: an actual asset file or a subfolder from a resources folder. The virtual $$anonymous$$erarchy is build up with t$$anonymous$$s class. T$$anonymous$$s class has several methods to navigate the $$anonymous$$erarchy or to search for a certain asset(s)

  • ResourceDB.GetFolder(path) t$$anonymous$$s method return a single ResourceItem for the given relative path. So if you have a folder like t$$anonymous$$s: Assets/Resources/sub1/sub2/folder you can pass the string "sub1/sub2/folder" and you get the ResourceItem for "folder".

  • ResourceDB.GetAllAssets(name, [type]) t$$anonymous$$s method returns an enumeration of multiple ResourceItems w$$anonymous$$ch match the given parameters. "name" has to be the exact asset name. It doesn't support partial names or wildcards but when you pass an empty string it will match any asset. The second optional type parameter allows you to specify a certain asset type. If t$$anonymous$$s parameter is null any asset will match. The type parameter supports inheritance. So passing typeof(Texture) will match any texture asset (Texture2D, RenderTexture, ...).

Besides those static methods of the ResourceDB class, the ResourceItem class also has similar functions:

  • GetC$$anonymous$$ld(path, [rType]) T$$anonymous$$s method allows you to access any c$$anonymous$$ld of the current ResourceItem. That ResourceItem has to represent a folder. When used on an asset resource it will return null. "path" is again a relative path w$$anonymous$$ch can be used to access deeper nested resources. The optional parameter "rType" allows you to specify if you only want assets, folders or both types.

  • GetC$$anonymous$$lds(name, [rType [, sub [, type]]]) T$$anonymous$$s method works similar to the GetAllAssets method above, however relative to the current folder and allows some additional settings. "name" again has to either match the actual filename or has to be an empty string to match any file / folder. With rType you can again specify if you want assets, folders or both. "sub" is a boolean w$$anonymous$$ch specifies if the method should only search in the current folder (false, default) or if it should include all sub folders (true). "type" is again a System,Type to filter assets for a certain type.

  • Load<T>() T$$anonymous$$s method allows you to directly load the resource represented by t$$anonymous$$s ResourceItem. It simply uses the "ResourcesPath" property of the ResourceItem w$$anonymous$$ch returns the complete assetpath needed for Resources.Load.

GetAllAssets as well as GetC$$anonymous$$lds return an IEnumerable<ResourceItem>. T$$anonymous$$s collection can either be iterated with a foreach loop, or converted into a List / array by using Linq.

The ResourceDB class is a singleton w$$anonymous$$ch loads itself from the Resources folder. So if you have created an ResourceDB asset in the editor you can use it anywhere in the project. Some examples:

 ResourceItem imagesFolder = ResourceDB.GetFolder("images");
 List<ResourceItem> imageItems = imagesFolder.GetC$$anonymous$$lds("",ResourceItem.Type.Asset, true, typeof(Texture2D)).ToList();

Each ResourceItem can be used to actually load the image it represents. You can use linq to batch-load all images into a Texture2D array / List:

 List<Texture2D> images = imageItems.Select(i=>i.Load<Texture2D>()).ToList();

It has some limitations when it comes to prefabs. Since a single prefab can represent an unlimited amount of different types, it's not supported to "search" for a specific component on a prefab. The DB will simply use and store the type of the main asset w$$anonymous$$ch is usually the GameObject. The same holds true for custom "assets" w$$anonymous$$ch contain multiple sub assets. However, loading should work just as usual.

So for example a terrain prefab (w$$anonymous$$ch is a GameObject with a Terrain script attached) can be loaded like t$$anonymous$$s:

 ResourceItem prefab; // we somehow obtained the ResourceItem for the prefab;
 Terrain terrain = prefab.Load<Terrain>();

Instead of using the Load function of ResourceItem, you could do the loading manually:

 string assetPath = prefab.ResourcesPath;
 Terrain terrain = Resources.Load<Terrain>(assetPath); // load as usual with Unity's Load method.

ps:
I hadn't much time to test all features and edge cases, so if you find any errors, feel free to leave a comment.

Comment
Fattie
Dave-Carlile
RobertWebb
MrFloat
Fornoreason1000
Thorny2000
karlthepagan
SunnySunshine
unityBerserker
Igor_Vasiak
gareth_untether
kyjv
Vedran_M

People who like this

13 Show 14 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Fattie · Jan 26, 2016 at 09:41 PM 0
Share

Got it, thanks for confirming that indeed it seems one "loses" the folder information, from, Project panel, once it rolls through to the actual game.

(I've sent along 10 RewardPoints to say thanks ... I wouldn't want to see someone struggling for points ;) )

I see the linked Anxo's code, good one, unfortunately it didn't help me figure out an Editor script :/

Basically I have a few hundred AudioClip, in some dozens of folders. Simply, at runtime, I want to know the name of each folder (category, if you will).

I can see two good approaches,

(A) Thank goodness these days, you can just select multiple AudioClip, and, set the values all at once, and drag them to the Hierarchy and it creates a gameobject+`AudioSource` for each one.

If it would additionally make "folders" for each folder, that is to say using an empty game object with the correct name, that would be the job done. I ask this here but it's too hard so far :)

Secondly per Axno's code if an editor script, very simply created a long text file that had, for each AudioClip (or indeed ... every asset would be fine) the name of the containing folder, again the job would be done.

Anyways that's what I had in mind, heh. Cheers!

avatar image Bunny83 Fattie · Jan 28, 2016 at 04:14 AM 0
Share

A "small" update ^^.

avatar image RobertWebb · Feb 19, 2016 at 01:52 AM 0
Share

Thanks for the code, this looks very useful. However I'm having some problems with it.

  • Works very well until I do a build (eg desktop PC or Android). Then ResourceDB.GetFolder() always just returns null. Seems the dictionary is empty for some reason.

  • When I exit and re-open Unity, selecting the ResourceDB asset, or running my app, or doing "Tools->Update ResourceDB" all lead to the same error about Unity calling a "pure virtual function call", after which it exits. I had to manually delete the ResourceDB.asset outside of Unity to get anything working again.

These are show-stoppers obviously. Is it just me? Thanks, Rob.

avatar image Bunny83 RobertWebb · Feb 19, 2016 at 02:58 AM 0
Share

Yes, i noticed that myself ^^. I've found a problem which i just fixed. I added a constructor that sets the static singleton variable:

 public ResourceDB()
 {
     m_Instance = this;
 }

The problem was when the ResourceDB asset got deserialized by Unity, the deserialization code accessed the singleton instance. If it's not initialized yet it tries to use Resources.Load to get the reference to the asset. However since that happens from Unity's serialization callback it caused problems.

This should also fix the null-ref problem at runtime.

I also changed the editor script as i forgot to mark the DB dirty when you toggle the autoupdate button. Now the state should be saved in the asset.

I've updated the files.

avatar image RobertWebb Bunny83 · Feb 22, 2016 at 01:47 AM 0
Share

Awesome! Yep thanks that fixed all the problems.

While I've got your ear, there's one other thing that would make this even nicer. The ability to limit the database to a given folder. I don't need all my resources, including resources relating to third party assets, in the database. I'd like to just create a folder called Assets/Resources/DB and tell it to only keep track of items under that folder. Would that be hard?

Thanks, Rob.

avatar image scaroni-tapps · Aug 08, 2016 at 07:50 PM 0
Share

Hey!! first of all thanks for sharing, really nice code, but i am having problems when building for android. It seems that the scriptable object reference is always missing, i dont know really why, i just know everything explodes when building for mobile devices, do you have any idea why?

avatar image cdoleseKKE · Aug 16, 2017 at 07:44 AM 0
Share

I see the links to ResourceDB.cs and ResourceDBEditor.cs are now returning file not found. I wanted to check and see if this was deliberate, or if they are still meant to be available? Really helpful answer though!

avatar image Bunny83 cdoleseKKE · Aug 18, 2017 at 07:11 PM 0
Share

Dropbox has removed the public folder feature. Now we have to explicitly create a link to each file seperately. I've updated the links.

avatar image SunnySunshine · Mar 19, 2018 at 07:53 PM 0
Share

Brilliant stuff. Thanks for sharing.

Show more comments

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

39 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Unity crashes while loading small assets 0 Answers

I'm using 4.5.4f1 version of Unity FREE and I can't find ANY assets. 1 Answer

I added some asset packages by mistake. How do I remove them? 1 Answer

Unity import assets crash 0 Answers

Can I use assets in game which i publish? Definite answer needed! (answered) 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges