Use this class attribute to register ObjectSelector search engines automatically. Search engines with this attribute must implement the IObjectSelectorEngine interface.
The following example shows how to create a new search engine that gets invoked when the user wants to select a material for a decal object.
using System; using System.Collections.Generic; using System.Linq; using UnityEditor; using UnityEngine; using UnityEditor.Search; using UnityEditor.SearchService; using UnityEngine.Search; class DecalPicker { [QueryListBlock("Decal", "Shader", "shader")] class ShaderDecalBlockList : QueryListBlock { public ShaderDecalBlockList(IQuerySource source, string id, string value, QueryListBlockAttribute attr) : base(source, id, value, attr) { } public override IEnumerable<SearchProposition> GetPropositions(SearchPropositionFlags flags = SearchPropositionFlags.None) { var shaderIcon = EditorGUIUtility.Load("Shader Icon") as Texture2D; yield return new SearchProposition(category: null, "HDRP Decal", "Decal", icon: shaderIcon); yield return new SearchProposition(category: null, "URP Decal", "DecalURP", icon: shaderIcon); } } const string k_Id = "decal_selector"; const string k_Name = "Decal Material Selector"; [AdvancedObjectSelectorValidator(k_Id)] static bool CanOpenSelector(ObjectSelectorSearchContext selectContext) { if ((selectContext.visibleObjects & UnityEditor.SearchService.VisibleObjects.Assets) == 0) return false; if (!selectContext.requiredTypes.All(t => typeof(Material).IsAssignableFrom(t))) return false; if (!selectContext.editedObjects.All(o => o?.GetType().Name.Contains("decal", StringComparison.OrdinalIgnoreCase) ?? false)) return false; var dbName = EnsureDecalPropertyIndexing(); if (dbName == null) return false; return true; } [AdvancedObjectSelector(k_Id, k_Name, 1)] static void SelectObject(AdvancedObjectSelectorEventType evt, in AdvancedObjectSelectorParameters args) { var selectContext = args.context; var dbName = EnsureDecalPropertyIndexing(); if (evt != AdvancedObjectSelectorEventType.OpenAndSearch) return; var selectHandler = args.selectorClosedHandler; var trackingHandler = args.trackingHandler; var query = SearchService.CreateContext(CreateDecalProvider(), $"a={dbName} t={selectContext.requiredTypeNames.First()} shader=Decal"); var viewState = new SearchViewState(query, CreateDecalsTableConfiguration(), SearchViewFlags.TableView | SearchViewFlags.OpenInBuilderMode | SearchViewFlags.DisableSavedSearchQuery); var materialIcon = EditorGUIUtility.Load("Material Icon") as Texture; viewState.windowTitle = new GUIContent("Material Decals", materialIcon); viewState.hideAllGroup = true; viewState.title = "decals"; viewState.selectHandler = (item, canceled) => selectHandler(item?.ToObject(), canceled); viewState.trackingHandler = (item) => trackingHandler(item?.ToObject()); viewState.position = SearchUtils.GetMainWindowCenteredPosition(new Vector2(600, 400)); SearchService.ShowPicker(viewState); } static SearchProvider CreateDecalProvider() { var assetProvider = SearchService.GetProvider("asset"); var decalProvider = SearchUtils.CreateGroupProvider(assetProvider, "Decals", 0, true); decalProvider.fetchPropositions = EnumerateDecalPropositions; return decalProvider; } static IEnumerable<SearchProposition> EnumerateDecalPropositions(SearchContext context, SearchPropositionOptions options) { if (!options.flags.HasAny(SearchPropositionFlags.QueryBuilder)) yield break; var shaderIcon = EditorGUIUtility.Load("Shader Icon") as Texture2D; yield return new SearchProposition(category: "Affects", label: "Base Color", replacement: "affectalbedo=1", icon: shaderIcon); yield return new SearchProposition(category: "Affects", label: "Normal", replacement: "affectnormal=1", icon: shaderIcon); yield return new SearchProposition(category: "Affects", label: "Metal", replacement: "affectmetal=1", icon: shaderIcon); yield return new SearchProposition(category: "Affects", label: "Ambient Occlusion", replacement: "affectao=1", icon: shaderIcon); yield return new SearchProposition(category: "Affects", label: "Smoothness", replacement: "affectsmoothness=1", icon: shaderIcon); yield return new SearchProposition(category: "Affects", label: "Emission", replacement: "affectemission=1", icon: shaderIcon); } static SearchTable CreateDecalsTableConfiguration() { var materialIcon = EditorGUIUtility.Load("Material Icon") as Texture; var shaderIcon = EditorGUIUtility.Load("Shader Icon") as Texture; return new SearchTable("decals", new SearchColumn[] { new SearchColumn("DecalsName0", "label", "name", new GUIContent("Name", materialIcon)) { width = 160 }, new SearchColumn("DecalsShader1", "#shader", "name", new GUIContent("Shader", shaderIcon)) { width = 150 }, new SearchColumn("DecalsBaseColor1", "#_BaseColor", "color", new GUIContent("Color", shaderIcon)) { width = 130 }, }); } static string EnsureDecalPropertyIndexing() { var materialDb = SearchService.EnumerateDatabases().FirstOrDefault(IsIndexingMaterialProperties); if (materialDb != null) return materialDb.name; if (!EditorUtility.DisplayDialog("Create decal material index", "Your project does not contain an index with decal material properties." + "\n\n" + "Do you want to create one now?", "Yes", "No")) return null; var dbName = "Decals"; SearchService.CreateIndex(dbName, IndexingOptions.Properties | IndexingOptions.Dependencies | IndexingOptions.Types | IndexingOptions.Keep, roots: null, includes: new string[] { ".mat" }, excludes: null, (name, path, finished) => { Debug.Log($"Material index {name} created at {path}"); finished(); }); return dbName; } static bool IsIndexingMaterialProperties(ISearchDatabase db) { if (string.Equals(db.name, "Materials", StringComparison.OrdinalIgnoreCase)) return true; return (db.indexingOptions & IndexingOptions.Properties) == IndexingOptions.Properties && (db.includePatterns.Count == 0 || db.includePatterns.Contains(".mat")); } }