- Home /
LoadAssetAtPath vs LoadAllAssetAtPath vs LoadMainAssetAtPath
Nice day everyone,
Recently I try to do some practice with unity editor script, I have not understand clearly about LoadAssetAtPath, LoadAllAssetAtPath, LoadMainAssetAtPath.
Say I have a prefabs at path ~/Assets/Resources/Prefabs/something.prefab As I understand if I use:
LoadAssetAtPath is load only one asset at that path. => I get the something.prefab object
LoadAllAssetAtPath is load all the asset at that path => I Get the something.prefab and the children object inside this prefab
LoadMainAssetAtPath is same with LoadAssetAtPath. => I get the something.prefab object (I don't know if this right or wrong, because as I test I get the same result with the LoadAssetAtPath) .
When I use LoadAllAssetAtPath, It's "seem like" some object has been duplicated. (I think so) for example, this is my test prefab:
something.prefab |_Tab1 |_child 1 |_child 2
I will got this result:
I hope someone here can teach me the different and the knowledge of these AssetDatabase feature. Thanks in advanced.
Answer by Bunny83 · Oct 23, 2017 at 03:28 AM
Well, you first should understand what Unity considers an "asset". In general every type that is derived from UnityEngine.Object could be called an asset as those are the only types Unity can serialize. Using LoadAllAssetAtPath on .prefab files doesn't make much sense as it would read out every single object that might be inside the prefab. Keep in mind that "GameObject" as well as "Transform" are serializable classes and they both share the same "name".
This method makes more sense for ".asset" files which contain multiple assets in a single file.An asset file could contain a serialized gameobject, a Material, maybe several Textures or any other asset like ScriptableObjects.
To understand this better i suggest you switch your "asset serialization mode" to "Force Text" (Edit-->Project Settings-->Editor-->Asset Serialization). This way you can open .prefab .scene or .asset files in a text editor. The text serialization is done in YAML.
To explain the difference between the three methods:
LoadAllAssetAtPath as mentioned simply loads all serialized objects it finds inside the specified file.
LoadMainAssetAtPath simply returns the "main" asset. This can be a bit confusing. Unity's built-in types have a "higher priority" than for example your ScriptableObject classes. That means if you save a ScriptableObject as .asset file you will see that instance in the inspector. However when you add a Material to the same file the Material will become the main asset. If no special priority applies this method will simply return the first asset that appears in the file.
LoadAssetAtPath loads a single asset from the file. It basically does almost the same as "LoadMainAssetAtPath" however you can specify a "filter type" so it only returns assets which are either of that type or derived from that type. So specifying "Texture" as type it will return any kind of texture asset (Texture2D, RenderTexture, Texture3D). Specifying "Component" will return the first asset that is a Component (might be the Transform component).
Now it might become clear that gameobjects actually don't have a hierarchy. GameObjects are just component containers. The Transform component actually creates the hierarchy relationship between different gameobjects.
If you imagine a gameobject as a single drawer in a file cabinet, it's registers inside would represent it's components. The drawers are simply next to each other and have no relation to each other. In one register (the Transform component) you may add a sticky note that says parent:"Drawer5D"
and it might have a list which lists the "children" of this object.
Note that the Transform component doesn't actually reference the parent / child gameobject(s) but rather their Transform components. Each Transform on the other hand has a reference to it's owning gameobject.
hmm, It's seem Transform is stronger than GameObject (I mean in the hierarchy manager side). GameObject just a containers and transform is the heart of this container (if I understand right).
So if I want to get only the object inside prefabs, I just simply filter out the transform type of the result of LoadAllAssetAtPath:D
wow, thanks a lot @Bunny83 . This answer is so clearly.
$$anonymous$$eep in $$anonymous$$d that "GameObject" as well as "Transform" are serializable classes and they both share the same "name".
I have never knew this. This know how so great.
About the Load$$anonymous$$ainAssetAtPath feature, as you mentioned it's base on the unity built-in type priorities, can you show me the detail of priorities compareation ? for example $$anonymous$$aterial and Script component, which will have the higher priorities...
Your answer is the best, but I will wait for 6 hours, after that if no better answer I will mark this accept. (Just because I want to hear more info and compare it)
Thanks
"Script Components" will never be the main asset since components can be seen as "child" objects of GameObjects. They can't "live" without a GameObject. Your own scripts are not built in types and therefore will never be the main asset if there's also a built-in asset next to it in the same asset file. I can't give you an exact "order" as I haven't tested this out. All I can say is that for example ScriptableObjects have pretty much the same "priority" and therefore their ordering is random. This is very annoying. I once created a ScriptableObject which represented a node based tree. I don't want to have each node as a seperate asset so i simply added all nodes as objects to the same asset and "my main" ScriptableObject just holds a list which references those other assets. Unfortunately Unity picked some random node as main asset and my main asset showed up as "child" between the other nodes.
If you don't need direct access to the individual nodes it's possible to set their hideFlags appropriately so they don't show up in the project view. When the main asset is the only visible asset it will show as the main asset.
Hopefully this can improved in the far future. All Unity would need to do is keep the ordering inside the asset, provide ways to change the order (like the component ordering which got added somewhere in the Unity 5.x cycle) and just pick the first object as main asset.
Note that all Components have a "name", "tag", "transform" and "gameObject" property. However they just access the name, tag and transform of the gameobject they are attached to.
Ya, as your explanation, the thinking "Load$$anonymous$$ainAssetAtPath is a redundant feature" come to my head. I can not find out any case to use it efficiently at the moment. All it's do is just mess up things. The "priorities" information is really helped me understand some problems.
If you're more interested in understanding Unity's YA$$anonymous$$L format. Unity has some documentation over here. A list with the numerical built-in class types can be found over here
A line like this:
--- !u!1 &6
actually specifies the type of the object (in this case "1" == GameObject) and a local reference "fileID" == "6". This will be used by other objects in the same file to reference this object.
Your ref is so amazing. I have interesting in this. Thanks so much @Bunny83 I will try ma best to know more about the YA$$anonymous$$L file. I think I can do something with this.