// 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;
}
}
}