Skip to content

Instantly share code, notes, and snippets.

@thebne
Last active August 28, 2023 11:59
Show Gist options
  • Save thebne/f42c0de9e0361e49e89931b7f7a53853 to your computer and use it in GitHub Desktop.
Save thebne/f42c0de9e0361e49e89931b7f7a53853 to your computer and use it in GitHub Desktop.
UnityEditor - FindAssetsByTypeAsync and LoadAssetAsync (UniTask async wrapper, automatically finding localId)
public static class EditorUtils
{
public static async IAsyncEnumerable<T> FindAssetsByTypeAsync<T>() where T : UnityEngine.Object
{
var queue = ListPool<UniTask<T>.Awaiter>.Get();
try
{
foreach (string guid in guids)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
queue.Add(LoadAssetAsync<T>(assetPath).GetAwaiter());
}
while (queue.Count > 0)
{
for (int i = 0; i < queue.Count; i++)
{
if (queue[i].IsCompleted)
{
yield return queue[i].GetResult();
queue.RemoveAt(i);
i--;
}
}
await UniTask.Yield();
}
}
finally
{
ListPool<UniTask<T>.Awaiter>.Release(queue);
}
}
public static async UniTask<T> LoadAssetAsync<T>(string path) where T : UnityEngine.Object
{
var utcs = new UniTaskCompletionSource<T>();
var mainObjectId = await GetMainObjectFileIDAsync(path);
if (mainObjectId == 0)
{
mainObjectId = await ResolveFallbackMainObjectFileIdAsync(path);
}
var op = AssetDatabase.LoadObjectAsync(path, mainObjectId);
void OnCompleted(AsyncOperation asyncOperation) {
op.completed -= OnCompleted;
utcs.TrySetResult(op.LoadedObject as T);
}
op.completed += OnCompleted;
return await utcs.Task;
}
private static async UniTask<int> GetMainObjectFileIDAsync(string assetPath)
{
string metaFilePath = assetPath + ".meta";
if (File.Exists(metaFilePath))
{
string metaFileContent = await File.ReadAllTextAsync(metaFilePath);
Match match = Regex.Match(metaFileContent, @"mainObjectFileID: (-?\d+)");
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int mainObjectFileID))
{
return mainObjectFileID;
}
}
}
throw new Exception("Meta file not found or mainObjectFileID not present");
}
private static async UniTask<int> ResolveFallbackMainObjectFileIdAsync(string assetPath)
{
// https://docs.unity3d.com/Manual/ClassIDReference.html
// assume main object id = class id * 100000
// --- !u!114 &11400000
// --- !u!x &x00000
if (File.Exists(assetPath))
{
string fileContent = await File.ReadAllTextAsync(assetPath);
// try to find a match that has the !u!x &x00000 parity
Match match = Regex.Match(fileContent, @"--- !u!(?<classid>\d+) &(\k<classid>00000)");
if (match.Success)
{
if (int.TryParse(match.Groups[1].Value, out int localId))
{
return localId;
}
}
}
throw new Exception("Asset file not found or fallback mainObjectFileID not found");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment