Search Unity

Loading Prefabs from custom folder?! (NOT /Resources)

Discussion in 'Scripting' started by TheGabeMeister, Jul 6, 2014.

  1. TheGabeMeister

    TheGabeMeister

    Joined:
    Jul 6, 2014
    Posts:
    7
    Hi everyone. I will get straight to the point here. I am making a game and plan to allow the user to add custom objects. I have this working perfect with custom levels (XML files) but I don't know how to do it with GameObjects/Prefabs.

    Usually I would use "Resources.Load()" but I need to load assets from a custom file in the build directory.

    This is what I have:

    DirectoryInfo info = new DirectoryInfo(Application.dataPath + "/Resources/CustomObjects");
    FileInfo[] fileInfo = info.GetFiles();
    List<GameObject> CustomObjects = new List<GameObject>();

    for (int i = 0; i < fileInfo.Length; i++)
    {
    CustomObjects.Add(Asset.Load(Application.dataPath + "/Resources/CustomObjects" + fileInfo.Name) as GameObject);
    }

    Obviously there is no "Asset.Load()" but this is what I expect. Can anybody help me out?

    Thanks,
     
    Last edited: Jul 6, 2014
    CloudyVR likes this.
  2. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    as far as I know this is not possible to do (Im not taking into account asset bundles however, as I dont own unity pro). So I'm planning on creating my own serialisation/deserialisation system for models, components etc.

    There might be a possibility if you use some reflection trickery, but it is of course not supported, nor recommended (thus I haven't looked into this option either. Besides, the concept of prefabs is probably editor-only anyway)

    If someone else has an answer, I'd be pleased to know what the other alternatives are as well
     
  3. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Unity's class can only be loaded from its own specific method like Resources.Load or AssetBundles. Sadly, even Reflection trickery won't help you there because the load is not happening in the C# assemblies, but in the C++ engine.

    If for some reason you REALLY want to do that, you will have to write your own serialization that reflect the GameObject structure, and rebuild the GameObject from that data.
     
    IvanAuda likes this.
  4. PrefabEvolution

    PrefabEvolution

    Joined:
    Mar 27, 2014
    Posts:
    225
    Inside editor you can probably use Resources.LoadAssetAtPath(assetFolderRelativePath). But in build this function will return null. Another way is to make some ScriptableObject that will contains all assets that you would like to use:
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5.  
    6. public class MyResources : ScriptableObject
    7. {
    8.     [System.Serializable]
    9.     private class ResourceInfo
    10.     {
    11.         public string path;
    12.         public Object asset;
    13.     }
    14.  
    15.     [SerializeField]
    16.     private List<ResourceInfo> resources;
    17.  
    18.     static private MyResources instance;
    19.  
    20.     static private MyResources Instance
    21.     {
    22.         get
    23.         {
    24.             if (instance == null)
    25.             {
    26.                 instance = Resources.Load("MyResources") as MyResources;
    27.             }
    28.             return instance;
    29.         }
    30.     }
    31.  
    32.     static public Object Load(string path)
    33.     {
    34.         var record = Instance.resources.FirstOrDefault(resource => resource.path == path);
    35.         return record == null ? null : record.asset;
    36.     }
    37.  
    38.     static public T Load<T>(string path) where T:Object
    39.     {
    40.         return Load(path) as T;
    41.     }
    42.     #if UNITY_EDITOR
    43.     [UnityEditor.MenuItem("Assets/Create/MyResources")]
    44.     static void Create()
    45.     {
    46.         var asset = ScriptableObject.CreateInstance<MyResources>();
    47.         var path = "Resources/MyResources.asset";
    48.         UnityEditor.AssetDatabase.CreateAsset(asset, path);
    49.         UnityEditor.AssetDatabase.ImportAsset(path);
    50.     }
    51.     #endif
    52. }
    53.  
    54.  
    55.  
    But be careful, all assets will be loaded into the memory when you load this asset. Buy the other hand all asset that are loaded with Resource.Load will be unloaded only after you call Resources.UnloadAsset or Resources.UnloadUnusedAssets.
     
    Last edited: Jul 6, 2014
  5. TheGabeMeister

    TheGabeMeister

    Joined:
    Jul 6, 2014
    Posts:
    7

    Firstly, very good work on your Sandbox game. I will be excited to see how it is when it's done!!

    Secondly, thank you for the answer. If only there was a Resources folder in the build directory ;(. I suppose all the data could be stored as text (Mesh, components etc. like you say) but I imagine that will take some time to crack. I will work it out one of these days but for now, I guess I may as well complete the rest of my game as it would be better to get a prototype/concept game finished and then finalise everything, including custom objects then spending a lot of time implementing custom objects and then finishing the prototype.

    Thanks,
     
  6. TheGabeMeister

    TheGabeMeister

    Joined:
    Jul 6, 2014
    Posts:
    7
    I love seeing everyone's projects at the bottom of their post! Good work. Thank you for the answer, If there is no "easy" way to this I will look at it again at a later date as I have other parts of my project to complete that will make up the prototype (custom objects not entirly needed for the prototype).
     
  7. TheGabeMeister

    TheGabeMeister

    Joined:
    Jul 6, 2014
    Posts:
    7

    Good work with your "Prefab Evolution"! Thanks for the reply. I will look into this later as it seems qutie interesting.

    Thanks,
     
  8. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    938
    Yeah I supposed so.. That will be the plan then I guess.

    Thank you :) I am probably as excited to see how it turns out as you are :p

    Yeah it will take some time to get that right. What you are suggesting was also my plan, to wait for the external serialisation and use the unity prefabs temporarily. It is indeed a good idea to get other stuff done first, before polishing the serialisation of gameobjects via external files
     
  9. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    Is there still no way of loading prefabs from folders other than Resources? I need to have different sets of prefabs for several different builds, which means I need to exclude some of the sets from each build. Right now, everything in Resources is included in each build. Is there any easy workaround for this? I don't think I want to write my own file handling system.
     
  10. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    The current solution is asset bundles.
     
  11. HonoraryBob

    HonoraryBob

    Joined:
    May 26, 2011
    Posts:
    1,214
    So I'd have to write an editor script to save each prefab as an assetbundle and then write code to load them in at runtime, or can I just load a normal prefab directly as an assetbundle?
     
  12. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    You do have to write some boiler plate code, but it's pretty minimal.
     
  13. tomrobin

    tomrobin

    Joined:
    May 25, 2018
    Posts:
    4
    old thread, I know, but I found a one line solution which works just fine in case someone else stumbles across this thread

    Code (CSharp):
    1. myGameObject = (GameObject)Instantiate((GameObject)AssetDatabase.LoadAssetAtPath("Assets/your/nonResources/path/fileName.prefab",typeof(GameObject)), currentPosition, currentRotation);
    the "Assets/your/nonResources/path/fileName.prefab" path can be located anywhere in your unity project where fileName is the name of the prefab you try to instatiate. For example "Assets/myPrefabs/buildings/house.prefab" would be a prefab called house that we saved under myPrefabs/buildings in the project view. currentPosition and currentRotation are Vector3 and Quaternions as per Instatiate command, nothing changed here.
     
  14. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Just be aware that AssetDatabase is only available in the editor. Which makes your solution fine for editor extensions, but it won't work in a built game.

    Edit: My current lazy solution is just to link everything into a scriptable object which is referenced via the scene.
     
    Last edited: Jul 12, 2018
    ZeroFlame and Mike_NHeart like this.
  15. tomrobin

    tomrobin

    Joined:
    May 25, 2018
    Posts:
    4
    i see, thanks for pointing that out. indeed for the editor it is just working fine
     
  16. landstalker310

    landstalker310

    Joined:
    Feb 22, 2018
    Posts:
    2

    Thanks, this is what I have been looking for
     
    mcroswell likes this.