BRP strict field in query (#16725)

# Objective

- Allow skiping components that don't have ComponentId yet instead of
failing `bevy/query` request.

## Solution

- Describe the solution used to achieve the objective above.

## Testing

My naive approach boils down to:
- bevy/list to get list of all components.
- bevy/query with empty components and has fields and a option that
contains result of the bevy/list.

Before that change I end up with bunch of `Component xxx isn't used in
the world` because some of the components wasn't spawned at any moment
yet in the game. Now it should work.

## Migration Guide

- `BrpQueryParams` now has `strict` boolean field. It serfs as a flag to
fail when encountering an invalid component rather than skipping it.
Defaults to false.
This commit is contained in:
MevLyshkin 2024-12-14 06:22:19 +01:00 committed by GitHub
parent 30bd641af4
commit 897ffad8af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 29 additions and 14 deletions

View File

@ -92,6 +92,11 @@ pub struct BrpQueryParams {
/// exclude from the results.
#[serde(default)]
pub filter: BrpQueryFilter,
/// An optional flag to fail when encountering an invalid component rather
/// than skipping it. Defaults to false.
#[serde(default)]
pub strict: bool,
}
/// `bevy/spawn`: Creates a new entity with the given components and responds
@ -527,19 +532,22 @@ pub fn process_remote_query_request(In(params): In<Option<Value>>, world: &mut W
has,
},
filter: BrpQueryFilter { without, with },
strict,
} = parse_some(params)?;
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
let type_registry = app_type_registry.read();
let components =
get_component_ids(&type_registry, world, components).map_err(BrpError::component_error)?;
let option =
get_component_ids(&type_registry, world, option).map_err(BrpError::component_error)?;
let has = get_component_ids(&type_registry, world, has).map_err(BrpError::component_error)?;
let without =
get_component_ids(&type_registry, world, without).map_err(BrpError::component_error)?;
let with = get_component_ids(&type_registry, world, with).map_err(BrpError::component_error)?;
let components = get_component_ids(&type_registry, world, components, strict)
.map_err(BrpError::component_error)?;
let option = get_component_ids(&type_registry, world, option, strict)
.map_err(BrpError::component_error)?;
let has =
get_component_ids(&type_registry, world, has, strict).map_err(BrpError::component_error)?;
let without = get_component_ids(&type_registry, world, without, strict)
.map_err(BrpError::component_error)?;
let with = get_component_ids(&type_registry, world, with, strict)
.map_err(BrpError::component_error)?;
let mut query = QueryBuilder::<FilteredEntityRef>::new(world);
for (_, component) in &components {
@ -659,8 +667,8 @@ pub fn process_remote_remove_request(
let app_type_registry = world.resource::<AppTypeRegistry>().clone();
let type_registry = app_type_registry.read();
let component_ids =
get_component_ids(&type_registry, world, components).map_err(BrpError::component_error)?;
let component_ids = get_component_ids(&type_registry, world, components, true)
.map_err(BrpError::component_error)?;
// Remove the components.
let mut entity_world_mut = get_entity_mut(world, entity)?;
@ -818,16 +826,20 @@ fn get_component_ids(
type_registry: &TypeRegistry,
world: &World,
component_paths: Vec<String>,
strict: bool,
) -> AnyhowResult<Vec<(TypeId, ComponentId)>> {
let mut component_ids = vec![];
for component_path in component_paths {
let type_id = get_component_type_registration(type_registry, &component_path)?.type_id();
let Some(component_id) = world.components().get_id(type_id) else {
if strict {
return Err(anyhow!(
"Component `{}` isn't used in the world",
component_path
));
}
continue;
};
component_ids.push((type_id, component_id));

View File

@ -142,6 +142,8 @@
//! on entities in order for them to be included in results.
//! - `without` (optional): An array of fully-qualified type names of components that must *not* be
//! present on entities in order for them to be included in results.
//! - `strict` (optional): A flag to enable strict mode which will fail if any one of the
//! components is not present or can not be reflected. Defaults to false.
//!
//! `result`: An array, each of which is an object containing:
//! - `entity`: The ID of a query-matching entity.

View File

@ -57,6 +57,7 @@ fn main() -> AnyhowResult<()> {
option: Vec::default(),
has: Vec::default(),
},
strict: false,
filter: BrpQueryFilter::default(),
})
.expect("Unable to convert query parameters to a valid JSON value"),