Search Unity

Using AssetDatabase.LoadAssetAtPath inside packages.

Discussion in 'Asset Database' started by Pixel2015, Jun 2, 2020.

  1. Pixel2015

    Pixel2015

    Joined:
    Mar 10, 2016
    Posts:
    35
    If I use AssetDatabase.LoadAssetAtPath inside packages it will return null. Is there a specific way on handling asset loading inside packages?

    Somewhere around here in a closed topic it was mentioned that the path should be without the version number. Ok fair enough but why AssetDatabase.GetAssetPath still returns with the version number. Or is there an additional helper method to strip it?

    I can do my own I would just like to know if this kind of confusing behaviour is intended.

    Thanks.
     
  2. Pixel2015

    Pixel2015

    Joined:
    Mar 10, 2016
    Posts:
    35
    So even with the stripped version number it doesn't load at all.

    What is the correct way of loading assets inside packages? Someone mentioned that you should copy the asset from the package path to the Unity project assets folder and load it from where. Really? That seems like a really dumb idea that just gets messy.
     
  3. Unity_Javier

    Unity_Javier

    Unity Technologies

    Joined:
    Mar 7, 2018
    Posts:
    190
    Hey, the way to load assets from packages is in the following way:

    Packages/[package_name]/path/to/asset/my_asset.extension

    So, in case you have the com.unity.2d.animation package installed, loading a file from there would be done via:

    Code (CSharp):
    1. var yellowDot = AssetDatabase.LoadAssetAtPath("Packages/com.unity.2d.animation/Editor/Assets/SkinningModule/dotYellow.png", typeof(Texture2D));
    And now yellowDot should be a Texture2D that you can use :)

    In case you don't know the path to the file, but know what the name should be you can use this code snippet to output what the path is:


    Code (CSharp):
    1. var allAssetPaths = AssetDatabase.GetAllAssetPaths();
    2. var fileName = "dotYellow.png";
    3. for(int i = 0; i < allAssetPaths.Length; ++i)
    4. {
    5.   if (allAssetPaths[i].EndsWith(fileName))
    6.       Debug.Log(allAssetPaths[i]);
    7. }
     
  4. Pixel2015

    Pixel2015

    Joined:
    Mar 10, 2016
    Posts:
    35
    Thanks, works now the problem was I used path starting with PackageCache instead of Packages :oops:
     
    ModLunar and Unity_Javier like this.
  5. van800

    van800

    JetBrains Employee

    Joined:
    May 19, 2016
    Posts:
    73
    How this works for local packages?
    My local package is outside the project:
    ```
    "com.test.package": "file:../../packages/MyLocalPackage",
    ```
    Full path didn't work.

    Update. This worked:
    ```
    var asset = AssetDatabase.LoadAssetAtPath(
    "Packages/com.test.package/Editor/SomeSubbolder/SomeScript.cs", typeof(Object));
    ```

    Is there a function in Unity, which can turn full path into that "relative" form for me?
     
    Last edited: Jul 16, 2021
  6. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
    @van800 if you only have an absolute path, we so far had to
    1. find all package.json in project (all the PackMan APIs, even the internal database ones, are way slower)
    2. get their Path.GetFullPath
    3. this gives you a mapping of virtual assetDB path to full path (e.g. "Packages/com.my.package/" => "C:/packages/MyPackage/")
    4. use that to map full paths back to relative ones
    Slow but works...


    If you have a virtual path to begin with you can just use
    Code (CSharp):
    1. var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssetPath(assetPath)
    2. var virtualPath = "Packages/" + packageInfo.name;
    3. var absolutePath = packageInfo.resolvedPath;
     
    megame_dev and Unity_Javier like this.
  7. van800

    van800

    JetBrains Employee

    Joined:
    May 19, 2016
    Posts:
    73
  8. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    802
  9. marwi

    marwi

    Joined:
    Aug 13, 2014
    Posts:
    138
    You know the package info (name + local file path) already when using "Show in Unity"?
    So why not just construct "Packages/<package-name>/relativePath/to/asset/to/show"?

    What am I missing ^^?

    What I've done in another project is (if the file is not inn assets):
    I use a cached list of packages infos from packman to find the package that starts with the absolute file path and then remove the package path from my absolute file path and add "Packages/<name>/relative/path", like this:

    Code (CSharp):
    1. if (PackageFilter.TryGetPackage(fp, out var package))
    2. {
    3.       var rel = "Packages/" + package.name + "/" + fp.Substring(package.resolvedPath.Length);
    4.       result = rel;
    5.       return File.Exists(result);
    6. }
     
    Last edited: Jul 19, 2021
    van800 likes this.
  10. van800

    van800

    JetBrains Employee

    Joined:
    May 19, 2016
    Posts:
    73
    I have made a generated solution with 100 local packages, each having 500 C# scripts and 500 . So 100000 assets total. For context in Unity 2021.2.0b10 first "Initial Asset Database Refresh" took 45 minutes. I don't have enough patience to wait for processing of even bigger project.

    I have the following test to measure iterating over all assets:
    Code (CSharp):
    1. [Test]
    2.         public void Test()
    3.         {
    4.             var sw = new Stopwatch();
    5.             sw.Start();
    6.             foreach (var asset in AssetDatabase.GetAllAssetPaths())
    7.             {
    8.                 var t = new FileInfo(Path.GetFullPath(asset)).FullName;
    9.             }
    10.             UnityEngine.Debug.Log(sw.Elapsed.Milliseconds);
    11.             sw.Reset();
    12.         }

    The test logs 707 ms for me.
    I have also checked "Show in Unity" feature manually on the same solution - it feels fast enough.
     
    Lanre and sandolkakos like this.