#if UNITY_EDITOR using System; using System.Collections.Generic; using System.Linq; using Jovian.Utilities; using Jovian.Utilities.Editor; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace Jovian.InspectorTools { public static class AutoFindUtil { public static void Search(AutoFindAttribute autoFindAttribute, SerializedProperty property, bool autoAddIfMissing = false) { Type propertyType = EditorSerializationUtility.GetTypeFromProperty(property); foreach (Object targetObject in property.serializedObject.targetObjects) { if (IsScopeGameObject(autoFindAttribute.scope)) { GameObject targetGameObject = ((Component)targetObject).gameObject; if (EditorSerializationUtility.IsPropertyAnArrayElement(property)) { SerializedProperty arrayProperty = EditorSerializationUtility.GetArrayPropertyWithElementProperty(property); EditorSerializationUtility.SaveObjectProperties( targetObject, arrayProperty.name, GetComponents(autoFindAttribute.scope, targetGameObject, propertyType, autoFindAttribute.filter)); } else { Component component = GetComponent(autoFindAttribute.scope, targetGameObject, propertyType, autoFindAttribute.filter); if (autoAddIfMissing && !component) { component = Undo.AddComponent(targetGameObject, propertyType); } EditorSerializationUtility.SaveObjectProperties( targetObject, property.name, component); } } else if (autoFindAttribute.scope == AutoFindScope.Scene) { IEnumerable componentsInHierarchy = FilterComponents(HierarchyUtility.FindComponentsInHierarchy(propertyType, true), autoFindAttribute.filter); if (EditorSerializationUtility.IsPropertyAnArrayElement(property)) { SerializedProperty arrayProperty = EditorSerializationUtility.GetArrayPropertyWithElementProperty(property); EditorSerializationUtility.SaveObjectProperties( targetObject, arrayProperty.name, componentsInHierarchy); } else { EditorSerializationUtility.SaveObjectProperties( targetObject, property.name, componentsInHierarchy.FirstOrDefault()); } } else if (autoFindAttribute.scope == AutoFindScope.Project) { if (EditorSerializationUtility.IsPropertyAnArrayElement(property)) { SerializedProperty arrayProperty = EditorSerializationUtility.GetArrayPropertyWithElementProperty(property); List assets = autoFindAttribute.isPrefab ? AssetUtility.FindAllPrefabsInProject(propertyType, autoFindAttribute.filter) : AssetUtility.FindAllAssetsInProject(propertyType, autoFindAttribute.filter); EditorSerializationUtility.SaveObjectProperties( targetObject, arrayProperty.name, assets ); } else { Object asset = autoFindAttribute.isPrefab ? AssetUtility.FindPrefabInProject(propertyType, autoFindAttribute.filter) : AssetUtility.FindAssetInProject(propertyType, autoFindAttribute.filter); EditorSerializationUtility.SaveObjectProperties( targetObject, property.name, asset ); } } } } private static bool IsScopeGameObject(AutoFindScope scope) { switch (scope) { case AutoFindScope.Self: case AutoFindScope.SelfAndChildren: case AutoFindScope.SelfAndParent: return true; } return false; } private static Component GetComponent(AutoFindScope scope, GameObject gameObject, Type componentType, string filter = null) { return GetComponents(scope, gameObject, componentType, filter).FirstOrDefault(); } private static IEnumerable GetComponents(AutoFindScope scope, GameObject gameObject, Type componentType, string filter = null) { switch (scope) { case AutoFindScope.Self: List result = new(); Component component = gameObject.GetComponent(componentType); if (component != null) { result.Add(component); } return FilterComponents(result, filter); case AutoFindScope.SelfAndChildren: return FilterComponents(gameObject.GetComponentsInChildren(componentType, true), filter); case AutoFindScope.SelfAndParent: return FilterComponents(gameObject.GetComponentsInParent(componentType, true), filter); case AutoFindScope.Scene: case AutoFindScope.Project: throw new NotSupportedException($"{scope} is not supported with GetComponents"); default: throw new ArgumentOutOfRangeException(nameof(scope), scope, null); } } private static IEnumerable FilterComponents(IEnumerable components, string filter) { return string.IsNullOrEmpty(filter) ? components : components.Where(c => FilterMatchesName(c.name, filter)); } private static bool FilterMatchesName(string name, string filter) { return name.Contains(filter, StringComparison.InvariantCultureIgnoreCase); } } } #endif