Code Recipe: AssetDatabaseUtility

📆 Created on March 22, 2023. 🔖 programmingunity3dunity-editor

Working in Unity can be a frustrating endeavor, especially when working with the AssetDatabase. It's public methods just aren't all that helpful, at least in most of the cases where I've needed to use it.

So I've built out a helper class that makes working with assets a lot easier and I wanted to open source it in the hopes that maybe someone else finds it useful one day.

AssetDatabaseUtility

You can check out the code here, in the Noir.Unity project. It's MIT licensed so please use it or remix it as you need.

The class has three methods, each of which are pretty well documented both in the code and on the docs site for the library, but I'll give a quick overview of them here.

Mkdirp(String)

If you've used the command line mkdir -p then you know what this does. It takes a relative path like some/path/to/some/thing and ensures it's full hierarchy is created within the Assets/ folder.

TryGetReferencesToObject(UnityEngine.Object, out IEnumerable)

This method searches through the asset database looking for any asset that has a reference to the given GameObject. The path to each asset file will be returned in the IEnumerable. This does read the contents of all the assets on the disk, so definitely cache the results and don't call this in a loop.

This is really useful if you're using scriptable objects as data containers or event messages. You can find out exactly which objects have a reference to in the editor so you can know if an event is safe to delete or what needs to be tested if you change a weapon.

private void RenderMetadata(NoirGameEvent ev) {
EditorGUI.indentLevel++;
if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(ev, out var guid, out long localId)) {
using (new EditorGUILayout.HorizontalScope()) {
using (new EditorGUILayout.VerticalScope()) {
EditorGUILayout.SelectableLabel($"ID: {guid}");
EditorGUILayout.SelectableLabel($"Local ID: {localId}");
}
if (GUILayout.Button("Refresh Consumers") &&
AssetDatabaseUtility.TryGetReferencesToObject(ev, out var usedBy)) {
if (_eventUsedByTracker.ContainsKey(guid))
_eventUsedByTracker[guid] = usedBy;
else _eventUsedByTracker.Add(guid, usedBy);
}
}
}

EditorGUI.indentLevel--;
}

Load(String, Func<String, Boolean>, String[])

This method is the first method I wrote for the helper and it's definitely the most used out of all of them in my projects. This searches the asset database for assets of a certain type, loads them and returns them. You can filter the results a few different ways:

  1. Passing a search query. Any query from the search field in the project tab will work.
  2. Passing a predicate Func that will get called with the path to each asset that matches the given type or query.
  3. Setting a specific set of directories to search through.

Here's an example

// find all assets with GameLevel behaviour,
// the "Level" label and only look within
// the Assets/Prefabs/Levels directory
var levels = AssetDatabaseUtility.Load<GameLevel>(
"l:Level",
searchPaths: "Assets/Prefabs/Levels");

You can check out the code here, in the Noir.Unity project and on the docs site for the library. It's MIT licensed so please use it or remix it as you need.

Until next time! You can always shoot me your thoughts on twitter.

Previous Pixel Art Emission Maps Next Code Recipe: CustomAssertions