Possibilities to load uss/uxml when distributed as package?

Hey guys!
First let me say that I was REALLY looking forward to use UIElements and the new System … it’s awesome!

After I had my first dive into UIElements and built my first UIs with it i decided to build an UI for an Editor tool I’ve built with it. I did specify the paths to the uss / uxml files by hardcoding them and loading them via the AssetDatabase like this

string path = "Assets/MyAwesomeTool/Editor/EntityTypeDefinitionEditor";

_visualTree = AssetDatabase.LoadAssetAtPath<VisualTreeAsset> (Path.Combine(path, "EntityTypeDefinitionTemplate.uxml"));

StyleSheet styleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet> (Path.Combine(path,
                      "EntityTypeDefinitionStyle.uss"));

but of course this breaks as soon as I distribute my tool as a package via GitHub (or the AssetStore)

How can I specify the paths more solid to also work from folders not inside the Asset folder (like for packages e.g. ./Library/PackageCache/de.oma.tools.myawesometool@8f41bd4884/Editor/EntityTypeDefinitionEditor/EntityTypeDefinitionStyle.uss)

I’m using 2019.3.14 / UIBuilder 0.11.2

Thanks for your help!

Best, Cxyda

As always … you find the solution yourself right after you posted the question on the internet :rage:

What i did:

public static T LoadFirstAssetByFilter<T>(string assetFilter,  string[] searchInFolders = null) where T : UnityEngine.Object
{
     var guids = AssetDatabase.FindAssets(assetFilter, searchInFolders);
     if (guids.Length > 0)
     {
          var assetPath = AssetDatabase.GUIDToAssetPath(guids[0]);
          return AssetDatabase.LoadAssetAtPath<T>(assetPath);
     }

     Debug.LogError($"Unable to find asset '{assetFilter}'");

     return null;
}

Is there an even better way ?

as far as i know you can access the package folder with

AssetDatabase.LoadAssetAtPath<T>("Packages/de.oma.tools.myawesometool/Editor/EntityTypeDefinitionEditor")

Even if your package folder is named “MyAwesomeTool” you need to use “de.oma.tools.myawesometool”

Just put your assets into a Resources folder and use the Resources.Load(relativePath).

1 Like

hey there !Thanks for the answers!

putting it to a Resources would include my Editor UIs always into the builds right? This is unfortunately no option then :frowning:

Thanks silenterus i will try that !

No, If the Resources folder is inside the Editor folder it will be ignored. Docs

2 Likes

Hey, the AssetDatabase.FindAssets() is generally the most used approach, but that does traverse the entire project which, after a certain size, can get a bit heavy to do.

If you’re confident that your asset is immutable, you could hardcode the GUID for it and load it similar to your example.

To find the GUID of an asset, you can look in its corresponding .meta file.

So, if for example you have the com.unity.2d.animation package installed, inspecting the .meta file for dotYellow.png and dotCyan.png gives these 2 GUIDs:
173a5eb1d13d68d4ea39f3e5d2c6e2c0
5b56cb1a6bd97f348b3a3b6f875aafd6

Then, expanding your example:

    [MenuItem("AssetDatabase/Immutable GUIDs")]
    public static void LoadAssetsFromKnownGUIDs()
    {
        var textures = LoadMyAssets<Texture2D>(new[] { "173a5eb1d13d68d4ea39f3e5d2c6e2c0", "5b56cb1a6bd97f348b3a3b6f875aafd6" });

        foreach (var curTexture in textures)
        {
            Debug.Log($"Texture: {curTexture.name}, width:{curTexture.width}, height:{curTexture.height}");
        }
    }

    public static T[] LoadMyAssets<T>(string[] guids) where T : UnityEngine.Object
    {
        T[] assets = new T[guids.Length];
        if (guids.Length > 0)
        {
            int i = 0;
            foreach (var curGUID in guids)
            {
                var assetPath = AssetDatabase.GUIDToAssetPath(curGUID);
                assets[i] = AssetDatabase.LoadAssetAtPath<T>(assetPath);
                ++i;
            }
        }

        return assets;
    }

Is another approach with some different requirements, but it would scale with project size :slight_smile:

Another way of getting the GUID is to read it out directly from the AssetDatabase using another tool.
I found myself hardcoding GUIDS often for loading assets that are in the project / package that I make myself.

I made a simple Editor tool that has an object field, just drag drop the asset in there and request the GUID using AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(ObjectField));
And for a copy button you can use EditorGUIUtility.systemCopyBuffer = guid;

Maybe ever, unity will provide a way in the inspector to get / copy the GUID?

1 Like