#if UNITY_EDITOR using DTT.Utils.EditorUtilities.Exceptions; using System; using System.IO; using DTT.Utils.Exceptions; using UnityEditor; using UnityEditorInternal; using UnityEngine; namespace DTT.Utils.EditorUtilities { /// /// A static utility class for retrieving data from the Unity Asset Database. /// public class AssetDatabaseUtility { /// /// Returns an array of assets loaded of from the /// asset database using given filter argument. /// /// The filter to use for finding the assets. /// The folders to look in when searching. /// The array of assets retrieved from the asset database. public static T[] LoadAssets(string filter, string[] searchFolders = null) where T : UnityEngine.Object { // Guids are found in search folders if there are any given. string[] guids = searchFolders == null ? AssetDatabase.FindAssets(filter) : AssetDatabase.FindAssets(filter, searchFolders); T[] array = new T[guids.Length]; for (int i = 0; i < array.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); array[i] = AssetDatabase.LoadAssetAtPath(path); } return array; } /// /// Returns an array of assets loaded of from the /// asset database. /// /// The folders to look in when searching. /// The array of assets retrieved from the asset database. public static T[] LoadAssets(string[] searchFolders = null) where T : UnityEngine.Object { string filter = string.Format("t:{0}", typeof(T).Name); // Guids are found in search folders if there are any given. string[] guids = searchFolders != null ? AssetDatabase.FindAssets(filter, searchFolders) : AssetDatabase.FindAssets(filter); T[] array = new T[guids.Length]; for (int i = 0; i < array.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(guids[i]); array[i] = AssetDatabase.LoadAssetAtPath(path); } return array; } /// /// Returns an asset of from the /// asset database. /// If there are multiple it will return the first one found. /// /// The filter to use for finding the asset /// The folder to look in when searching. /// The asset retrieved from the asset database. public static T LoadAsset() where T : UnityEngine.Object { T[] assets = LoadAssets(); return assets.Length != 0 ? assets[0] : null; } /// /// Returns a loaded asset of from the /// asset database using given filter argument. /// If there are multiple it will return the first one found. /// /// The filter to use for finding the asset /// The folder to look in when searching. /// The asset retrieved from the asset database. public static T LoadAsset(string filter) where T : UnityEngine.Object { if (filter == null) throw new AssetDatabaseException("Filter is null."); T[] assets = LoadAssets(filter); return assets.Length != 0 ? assets[0] : null; } /// /// Returns a loaded asset of from the /// asset database using given filter argument. /// If there are multiple it will return the first one found. /// /// The filter to use for finding the asset /// The folder to look in when searching. /// The asset retrieved from the asset database. public static T LoadAsset(string filter, string searchFolder) where T : UnityEngine.Object { T[] assets = LoadAssets(filter, new string[] { searchFolder }); return assets.Length != 0 ? assets[0] : null; } /// /// Saves and refreshes assets after the inspectors have been updated. /// Use a delayed call for saving assets when saving instantly causes a Unity-problem that /// will occur whenever an inspector previewing an asset is open while starting playmode. /// public static void SaveAndRefreshAssetsDelayed() { EditorApplication.delayCall += SaveAndRefresh; void SaveAndRefresh() { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); EditorApplication.delayCall -= SaveAndRefresh; } } /// /// Returns a component attached to a prefab at given path. Will return null /// if the component was not attached. /// /// The type of component. /// The path the prefab can be found. /// The component attached to the prefab. public static T GetComponentInPrefab(string prefabPath) where T : Component { if (string.IsNullOrEmpty(prefabPath)) throw new NullOrEmptyException(nameof(prefabPath)); GameObject prefab = AssetDatabase.LoadAssetAtPath(prefabPath); if (prefab == null) { if(File.Exists(prefabPath)) throw new AssetDatabaseException($"Failed to load asset even though it exists at path {prefabPath}. " + "This can happen when changes outside of Unity have been made to your asset and you load it " + "during project startup with attributes like [DidReloadScripts] and [InitializeOnLoad]."); throw new AssetDatabaseException($"Prefab can't be loaded at path {prefabPath}"); } return prefab.GetComponent(); } /// /// Tries returning a loaded scriptable object asset at given path but creates it if /// it didn't exist. /// This operation will not save the asset if it has been created. /// /// The type of scriptable object asset. /// The path at which to load or create. /// The loaded or created scriptable object asset reference. public static T GetOrCreateScriptableObjectAsset(string path) where T : ScriptableObject { if (File.Exists(path)) { T asset = AssetDatabase.LoadAssetAtPath(path); if (asset == null) { throw new AssetDatabaseException($"Failed to load asset even though it exists at path {path}. " + "This can happen when changes outside of Unity have been made to your asset and you load it " + "during project startup with attributes like [DidReloadScripts] and [InitializeOnLoad]."); } return asset; } T instance = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(instance, path); return instance; } /// /// Tries returning a loaded scriptable object asset at given path but creates it if /// it didn't exist. /// This operation will not save the asset if it has been created. /// /// The type of scriptable object asset. /// The path at which to load or create. /// Whether the asset could not be found and was created. /// The loaded or created scriptable object asset reference. public static T GetOrCreateScriptableObjectAsset(string path, out bool wasCreated) where T : ScriptableObject { wasCreated = false; if (File.Exists(path)) { T asset = AssetDatabase.LoadAssetAtPath(path); if (asset == null) { throw new AssetDatabaseException($"Failed to load asset even though it exists at path {path}. " + "This can happen when changes outside of Unity have been made to your asset and you load it " + "during project startup with attributes like [DidReloadScripts] and [InitializeOnLoad]."); } return asset; } wasCreated = true; T instance = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(instance, path); return instance; } /// /// Creates a prefab asset at given path using given GameObject instance. /// Will destroy the instance if the creation was succesful. /// /// This function doesn't return a prefab reference since there /// is no certainty it can be created instantly. /// /// /// The path at which to create the prefab. /// /// The GameObject instance to use for creating the prefab. /// public static void CreatePrefabAtPath(string path, GameObject instanceRoot) { try { var prefab = PrefabUtility.SaveAsPrefabAsset(instanceRoot, path, out bool succes); if (succes) { Debug.Log($"Creating prefab at path: {path}"); if (prefab != null) Debug.Log($"{prefab} has been instantly created."); else Debug.Log("The prefab will be created after imports have finished."); } else { Debug.LogWarning("Failed creating prefab asset because saving failed."); } } catch (Exception e) { throw new AssetDatabaseException("Failed creating prefab.", e); } finally { GameObject.DestroyImmediate(instanceRoot); } } /// /// Opens a script asset. /// /// The script asset to open. public static void OpenScript(TextAsset scriptAsset) => OpenScript(AssetDatabase.GetAssetPath(scriptAsset), 0, 0); /// /// Opens a script at given path. /// /// The script asset path. public static bool OpenScript(string scriptAssetPath, int line = 0, int column = 0) { if (scriptAssetPath == null) throw new ArgumentNullException(nameof(scriptAssetPath)); return InternalEditorUtility.OpenFileAtLineExternal(scriptAssetPath, line, column); } /// /// Opens a prefab asset in prefab mode. /// /// The prefab to open in prefab mode. public static bool OpenPrefab(GameObject prefabAsset) { if (prefabAsset == null) throw new ArgumentNullException(nameof(prefabAsset)); return AssetDatabase.OpenAsset(prefabAsset); } } } #endif