Hey @sebastienp_unity ,
thanks for getting back to me!
- Why are you creating a new
SearchProvider? For which workflows?
- Which items will you be yielding?
I’m not 100% sure if I need a custom search provider and there might be a better way to do it, but here’s the context and what I’m trying to do:
We’re creating a RTS-type game that has many resources players need to gather. These resources can be used for various things such as construction materials, or as inputs for production chains, so there are various fields in our prefabs that reference these resources.
I’m trying to give our designers a quick and easy way to search through all of our prefabs for any use of a specific resource.
This can probably be achieved with the existing search features but I thought the friendliest way for our designers would be if they just have to click the “resource uses” search provider in the search window and then they just have to pick the resource they want to search for and that’s it.
For your code example:
I think that’s pretty much what I’m doing but I can’t get the drop down to show up on the query block.
There’s some changes I had to make to your example because unfortunately QueryListBlockAttribute.GetPropositions and QueryListBlock.CreateProposition are internal. From what I saw though they don’t seem to be doing anything super special.
Here’s what I got:
private class ResourceUsesSearchProvider : SearchProvider {
private readonly QueryEngine<AbstractConfiguredObjectAuthoring> queryEngine = new();
private readonly List<ResourceFilter> resourceFilters = new();
private readonly struct ResourceFilter {
public readonly ResourceType resourceType;
public ResourceFilter(ResourceType resourceType) {
this.resourceType = resourceType;
}
public bool containsResourceType(AbstractConfiguredObjectAuthoring abstractConfiguredObjectAuthoring) {
// ...
return false;
}
}
public ResourceUsesSearchProvider(string id, string displayName) : base(id, displayName) {
foreach (ResourceType value in Enum.GetValues(typeof(ResourceType))) {
resourceFilters.Add(new ResourceFilter(value));
}
foreach (ResourceFilter resourceFilter in resourceFilters) {
queryEngine.AddFilter(resourceFilter.resourceType.ToString(), resourceFilter.containsResourceType);
}
SearchValue.SetupEngine(queryEngine);
fetchItems = (context, items, provider) => FetchItems(context, provider);
fetchPropositions = FetchPropositions;
}
IEnumerable<SearchProposition> FetchPropositions(SearchContext context, SearchPropositionOptions options) {
foreach (ResourceFilter resourceFilter in resourceFilters) {
yield return new SearchProposition(category: "Resource Type", label: resourceFilter.resourceType.ToString(), resourceFilter.resourceType.ToString());
}
}
IEnumerable<SearchItem> FetchItems(SearchContext context, SearchProvider provider) {
if (context.empty)
yield break;
if (context.filterId != provider.filterId) {
yield break;
}
var query = queryEngine.ParseQuery(context.searchQuery);
using (var meshResults = SearchService.Request($"t:{nameof(AbstractConfiguredObjectAuthoring)}")) {
foreach (SearchItem result in meshResults) {
if (result == null) {
yield return null;
}
else {
AbstractConfiguredObjectAuthoring prefab = result.ToObject<AbstractConfiguredObjectAuthoring>();
if (prefab == null) {
Debug.LogWarning($"Invalid prefab: {result.id}");
continue;
}
bool isValid = query.Test(prefab);
if (isValid) {
yield return provider.CreateItem(context, AssetDatabase.GetAssetPath(prefab), null, null, null, null);
}
}
}
}
}
}
[QueryListBlock("Resource Uses", "resource_uses", "resource_uses", ":")]
class QueryLabelBlock : QueryListBlock {
public QueryLabelBlock(IQuerySource source, string id, string value, QueryListBlockAttribute attr)
: base(source, id, value, attr) {
}
public override IEnumerable<SearchProposition> GetPropositions(SearchPropositionFlags flags) {
foreach (ResourceType value in Enum.GetValues(typeof(ResourceType))) {
yield return new SearchProposition(category: "Resource Type", label: value.ToString(), value.ToString());
}
}
}
[SearchItemProvider]
internal static SearchProvider CreateProvider() {
return new ResourceUsesSearchProvider("resource_uses", "Resource Uses") {
priority = 99999, // Put example provider at a low priority
showDetailsOptions = ShowDetailsOptions.Inspector | ShowDetailsOptions.Actions | ShowDetailsOptions.Preview,
fetchThumbnail = (item, context) => AssetDatabase.GetCachedIcon(item.id) as Texture2D,
fetchPreview = (item, context, size, options) => AssetDatabase.GetCachedIcon(item.id) as Texture2D,
fetchLabel = (item, context) => AssetDatabase.LoadMainAssetAtPath(item.id)?.name,
fetchDescription = (item, context) => item.id,
toObject = (item, type) => AssetDatabase.LoadMainAssetAtPath(item.id),
trackSelection = TrackSelection,
startDrag = StartDrag,
};
}
I’m not entirely sure what the catgegory and name fields on QueryListBlock are so maybe I’ve got something wrong in there and that’s why it’s not showing up?