// Author: František Holubec // Created: 06.01.2022 // Copyright (c) Noxgames // http://www.noxgames.com/ using System; using System.Collections.Generic; using System.Globalization; using System.IO; using Sirenix.Utilities; using Sirenix.Utilities.Editor; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace NoxE.External.OdinExtensions.Editor { /// Utility functions for Unity assets. /// public static class EnhancedAssetUtilities { private static List componentListBuffer = new List(); private static readonly Type[] createableAssetTypes = new Type[3] { typeof(ScriptableObject), typeof(MonoBehaviour), typeof(GameObject) }; /// Gets all assets of the specified type. /// public static IEnumerable GetAllAssetsOfType() where T : Object { foreach (T obj in GetAllAssetsOfType(typeof(T))) yield return obj; } /// Gets all assets of the specified type. /// The type of assets to find. /// The asset folder path. /// public static IEnumerable GetAllAssetsOfType( Type type, string folderPath = null) { foreach (var assetSearchResult in GetAllAssetsOfTypeWithProgress(type, folderPath)) yield return assetSearchResult.Asset; } /// Gets all assets of the specified type. /// The type of assets to find. /// The asset folder path. /// public static IEnumerable GetAllAssetsOfTypeWithProgress( Type type, string folderPath = null) { var item = new AssetUtilities.AssetSearchResult(); if (folderPath != null) { folderPath = folderPath.Trim('/'); if (!folderPath.StartsWith("Assets/", StringComparison.InvariantCultureIgnoreCase)) folderPath = "Assets/" + folderPath; } if (type == typeof(GameObject)) { string[] assets; if (folderPath != null) assets = AssetDatabase.FindAssets("t:Prefab", new string[1] { folderPath }); else assets = AssetDatabase.FindAssets("t:Prefab"); var goGuids = assets; item.NumberOfResults = 0; foreach (var goGuid in goGuids) { foreach (var asset in AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GUIDToAssetPath(goGuid))) { if (asset is GameObject gameObject) { item.CurrentIndex = item.NumberOfResults; item.NumberOfResults++; item.Asset = gameObject; yield return item; } } } goGuids = null; } else if (type.InheritsFrom(typeof(Component))) { string[] assets; if (folderPath != null) assets = AssetDatabase.FindAssets("t:Prefab", new string[1] { folderPath }); else assets = AssetDatabase.FindAssets("t:Prefab"); var goGuids = assets; item.NumberOfResults = 0; foreach (var goGuid in goGuids) { foreach (var asset in AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GUIDToAssetPath(goGuid))) { if (asset is GameObject gameObject) { gameObject.GetComponents(type, componentListBuffer); item.CurrentIndex = item.NumberOfResults; item.NumberOfResults++; for (var j = 0; j < componentListBuffer.Count; ++j) { item.Asset = componentListBuffer[j]; yield return item; } } } } goGuids = null; } else { var str = type.FullName.StartsWith("UnityEngine.") || type.FullName.StartsWith("UnityEditor.") ? type.Name : type.FullName; string[] assets; if (folderPath != null) assets = AssetDatabase.FindAssets("t:" + str, new string[1] { folderPath }); else assets = AssetDatabase.FindAssets("t:" + str); var guids = assets; item.NumberOfResults = 0; foreach (var guid in guids) { foreach (var asset in AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GUIDToAssetPath(guid))) { if (type.IsInstanceOfType(asset)) { item.CurrentIndex = item.NumberOfResults; item.NumberOfResults++; item.Asset = asset; yield return item; } } } guids = null; } } /// Tests if an asset can be created from a type. /// The type to test. /// true if an asset can be created. Otherwise false. /// public static bool CanCreateNewAsset() { for (var index = 0; index < createableAssetTypes.Length; ++index) { if (typeof(T).InheritsFrom(createableAssetTypes[index])) return true; } return false; } /// Tests if an asset can be created from a type. /// The type to test. /// The base asset type. /// true if an asset can be created. Otherwise false. /// public static bool CanCreateNewAsset(out Type baseType) { for (var index = 0; index < createableAssetTypes.Length; ++index) { if (typeof(T).InheritsFrom(createableAssetTypes[index])) { baseType = createableAssetTypes[index]; return true; } } baseType = null; return false; } /// Gets project path to the specified asset. /// The asset object. /// The path to the asset. /// public static string GetAssetLocation(Object obj) { var assetPath = AssetDatabase.GetAssetPath(obj); return assetPath.Substring(0, assetPath.LastIndexOf('/')); } /// Creates a new asset of the specified type. /// The type of the asset. /// Project path to the new asset. /// The name of the asset. /// [Obsolete("This will eventually be removed and is only used by the AssetList attribute drawer. Use the AssetDatabase manually instead.")] public static void CreateNewAsset(string path, string assetName) where T : Object { Type baseType; if (!AssetUtilities.CanCreateNewAsset(out baseType)) { Debug.LogError("Unable to create new asset of type " + typeof(T).GetNiceName()); } else { if (path == null) { path = ""; } else { path = path.Trim().TrimStart('/').TrimEnd('/').Trim(); if (path.ToLower(CultureInfo.InvariantCulture).StartsWith("assets", StringComparison.InvariantCulture)) path = path.Substring(6, path.Length - 6).TrimStart('/'); } var path1 = Application.dataPath + "/" + path; if (!Directory.Exists(path1)) Directory.CreateDirectory(path1); assetName = assetName ?? typeof(T).GetNiceName(); if (assetName.IndexOf('.') < 0) assetName = assetName + "." + GetAssetFileExtensionName(baseType); path = AssetDatabase.GenerateUniqueAssetPath("Assets/" + path + "/" + assetName); GameObject go = null; Object asset; if (baseType == typeof(ScriptableObject)) asset = ScriptableObject.CreateInstance(typeof(T)); else if (baseType == typeof(MonoBehaviour)) { var gameObject = new GameObject(); gameObject.AddComponent(typeof(T)); asset = gameObject; go = gameObject; } else { if (baseType != typeof(GameObject)) throw new NotImplementedException(); asset = go = new GameObject(); } if (go != null) asset = PrefabUtility.CreatePrefab(path, go); else AssetDatabase.CreateAsset(asset, path); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); EditorGUIUtility.PingObject(asset); if (!(go != null)) return; Object.DestroyImmediate(go); } } private static string GetAssetFileExtensionName(Type type) { if (type == typeof(ScriptableObject)) return "asset"; return type == typeof(GameObject) || type == typeof(MonoBehaviour) ? "prefab" : null; } } }