Version: 2023.2
言語: 日本語

ObjectSelectorEngineAttribute

class in UnityEditor.SearchService

マニュアルに切り替える

説明

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"));
    }
}