版本:Unity 6 (6000.0)
语言英语
  • C#

SearchMonitor.GetView

建议更改

成功!

感谢您帮助我们提升 Unity 文档的质量。虽无法接受所有意见,但我们会阅读我们的用户建议的每一项更改,并在适当的情况下进行更新。

关闭

提交失败

由于某些原因,您的建议更改无法提交。请在几分钟后<a>再次尝试</a>。此外感谢您花时间帮助我们提升 Unity 文档的质量。

关闭

取消

声明

public static Search.SearchMonitorView GetView(bool delayedSync);

参数

delayedSync 布尔值,表示视图之间是否仅在释放视图时同步,或针对每一项操作同步。默认值为 false。

返回

SearchMonitorViewSearchMonitorView

说明

返回一个 SearchMonitorView,以访问搜索的主 PropertyDatabases

支持多次嵌套调用 GetView。如果这些调用位于同一线程上,它将返回同一实例,以避免开启和关闭新的视图。如果这些调用位于不同的线程上,将开启新的视图。以下是一个自定义场景 SearchProvider 的示例,它使用 GetView 将数据缓存到搜索的主 PropertyDatabases 中,以提高搜索速度

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Search;
using UnityEngine;

static class CustomSceneProvider
{
    const string k_ProviderId = "customSceneProvider";

    static QueryEngine<GameObject> s_QueryEngine;

    [SearchItemProvider]
    public static SearchProvider CreateSearchProvider()
    {
        return new SearchProvider(k_ProviderId, "Custom Scene")
        {
            filterId = "csp:",
            isExplicitProvider = true,
            fetchItems = (context, items, provider) => FetchItems(context, provider),
            onEnable = OnEnable
        };
    }

    static void OnEnable()
    {
        s_QueryEngine = new QueryEngine<GameObject>(true);
        s_QueryEngine.SetSearchDataCallback(go => new []{ go.name });
        s_QueryEngine.AddFilter("p", OnPropertyFilter, s => s, StringComparison.OrdinalIgnoreCase);

        // Setup all the SearchValue handlers.
        SearchValue.SetupEngine(s_QueryEngine);
    }

    static IEnumerable<SearchItem> FetchItems(SearchContext context, SearchProvider provider)
    {
        // Parse the search query.
        var query = s_QueryEngine.ParseQuery(context.searchQuery);
        if (query == null)
            yield break;

        // If there are any errors, report them.
        if (!query.valid)
        {
            foreach (var queryError in query.errors)
            {
                context.AddSearchQueryError(new SearchQueryError(queryError, context, provider));
            }
            yield break;
        }

        // Open a view on Search's main PropertyDatabases for the duration of the search. By opening
        // a view here, it reduces the time spent opening new views for each game object we filter in OnPropertyFilter.
        using (SearchMonitor.GetView())
        {
            var filteredObjects = query.Apply(SearchUtils.FetchGameObjects());
            foreach (var filteredObject in filteredObjects)
            {
                var instanceId = filteredObject.GetHashCode();
                yield return provider.CreateItem(context, instanceId.ToString(), ~instanceId, filteredObject.name, null, null, null);
            }
        }
    }

    static SearchValue OnPropertyFilter(GameObject go, string propertyName)
    {
        if (!go)
            return SearchValue.invalid;
        if (string.IsNullOrEmpty(propertyName))
            return SearchValue.invalid;

        // Opening a view here will only return the existing instance of the view if it's already open.
        using (var view = SearchMonitor.GetView())
        {
            var documentKey = GetDocumentKey(go);
            var propertyPath = GetPropertyPath(go, propertyName);
            var recordKey = PropertyDatabase.CreateRecordKey(documentKey, PropertyDatabase.CreatePropertyHash(propertyPath));
            if (view.TryLoadProperty(recordKey, out object data) && data is SearchValue sv)
                return sv;

            foreach (var c in EnumerateSubObjects(go))
            {
                var property = FindPropertyValue(c, propertyName);
                if (property.valid)
                {
                    view.StoreProperty(recordKey, property);
                    return property;
                }
            }

            view.StoreProperty(recordKey, SearchValue.invalid);
        }

        return SearchValue.invalid;
    }

    static IEnumerable<UnityEngine.Object> EnumerateSubObjects(GameObject go)
    {
        yield return go;

        var gocs = go.GetComponents<Component>();
        for (int componentIndex = 0; componentIndex < gocs.Length; ++componentIndex)
        {
            var c = gocs[componentIndex];
            if (!c || (c.hideFlags & HideFlags.HideInInspector) == HideFlags.HideInInspector)
                continue;

            yield return c;
        }
    }

    static SearchValue FindPropertyValue(UnityEngine.Object obj, string propertyName)
    {
        var property = FindProperty(obj, propertyName, out var so);
        if (property == null)
            return SearchValue.invalid;

        var v = SearchValue.ConvertPropertyValue(property);
        so?.Dispose();
        return v;
    }

    static SerializedProperty FindProperty(UnityEngine.Object obj, string propertyPath, out SerializedObject so)
    {
        if (!obj)
        {
            so = null;
            return null;
        }

        so = new SerializedObject(obj);
        var property = so.FindProperty(propertyPath);
        if (property != null)
            return property;

        property = so.FindProperty($"m_{propertyPath}");
        if (property != null)
        {
            return property;
        }

        property = so.GetIterator();
        var next = property.NextVisible(true);
        while (next)
        {
            if (property.name.EndsWith(propertyPath, StringComparison.OrdinalIgnoreCase) ||
                (property.name.Contains(" ") && property.name.Replace(" ", "").EndsWith(propertyPath, StringComparison.OrdinalIgnoreCase)))
            {
                return property;
            }
            next = property.NextVisible(property.hasChildren);
        }

        so?.Dispose();
        so = null;
        return null;
    }

    static ulong GetDocumentKey(GameObject go)
    {
        if (!go)
            return ulong.MaxValue;

        if (!go.scene.IsValid() || string.IsNullOrEmpty(go.scene.path))
            return ulong.MaxValue;

        // We return the scene path's hash code as the document key. This is the same key
        // that the SearchMonitor uses to invalidate assets that have been modified.
        return AssetDatabase.AssetPathToGUID(go.scene.path).GetHashCode64();
    }

    static string GetPropertyPath(GameObject go, string propertyName)
    {
        var hierarchyPath = SearchUtils.GetHierarchyPath(go);
        return $"{hierarchyPath}/{propertyName}";
    }

    static ulong GetHashCode64(this string strText)
    {
        if (string.IsNullOrEmpty(strText))
            return 0;
        var s1 = (ulong)strText.Substring(0, strText.Length / 2).GetHashCode();
        var s2 = (ulong)strText.Substring(strText.Length / 2).GetHashCode();
        return s1 << 32 | s2;
    }
}

请参阅 SearchMonitorView 了解更多详情。