#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