bevy/examples/ecs
Mark Wainwright f0a8994f55
Split WorldQuery into WorldQueryData and WorldQueryFilter (#9918)
# Objective

- Fixes #7680
- This is an updated for https://github.com/bevyengine/bevy/pull/8899
which had the same objective but fell a long way behind the latest
changes


## Solution

The traits `WorldQueryData : WorldQuery` and `WorldQueryFilter :
WorldQuery` have been added and some of the types and functions from
`WorldQuery` has been moved into them.

`ReadOnlyWorldQuery` has been replaced with `ReadOnlyWorldQueryData`. 

`WorldQueryFilter` is safe (as long as `WorldQuery` is implemented
safely).

`WorldQueryData` is unsafe - safely implementing it requires that
`Self::ReadOnly` is a readonly version of `Self` (this used to be a
safety requirement of `WorldQuery`)

The type parameters `Q` and `F` of `Query` must now implement
`WorldQueryData` and `WorldQueryFilter` respectively.

This makes it impossible to accidentally use a filter in the data
position or vice versa which was something that could lead to bugs.
~~Compile failure tests have been added to check this.~~

It was previously sometimes useful to use `Option<With<T>>` in the data
position. Use `Has<T>` instead in these cases.

The `WorldQuery` derive macro has been split into separate derive macros
for `WorldQueryData` and `WorldQueryFilter`.

Previously it was possible to derive both `WorldQuery` for a struct that
had a mixture of data and filter items. This would not work correctly in
some cases but could be a useful pattern in others. *This is no longer
possible.*

---

## Notes

- The changes outside of `bevy_ecs` are all changing type parameters to
the new types, updating the macro use, or replacing `Option<With<T>>`
with `Has<T>`.

- All `WorldQueryData` types always returned `true` for `IS_ARCHETYPAL`
so I moved it to `WorldQueryFilter` and
replaced all calls to it with `true`. That should be the only logic
change outside of the macro generation code.

- `Changed<T>` and `Added<T>` were being generated by a macro that I
have expanded. Happy to revert that if desired.

- The two derive macros share some functions for implementing
`WorldQuery` but the tidiest way I could find to implement them was to
give them a ton of arguments and ask clippy to ignore that.

## Changelog

### Changed
- Split `WorldQuery` into `WorldQueryData` and `WorldQueryFilter` which
now have separate derive macros. It is not possible to derive both for
the same type.
- `Query` now requires that the first type argument implements
`WorldQueryData` and the second implements `WorldQueryFilter`

## Migration Guide

- Update derives

```rust
// old
#[derive(WorldQuery)]
#[world_query(mutable, derive(Debug))]
struct CustomQuery {
    entity: Entity,
    a: &'static mut ComponentA
}

#[derive(WorldQuery)]
struct QueryFilter {
    _c: With<ComponentC>
}

// new 
#[derive(WorldQueryData)]
#[world_query_data(mutable, derive(Debug))]
struct CustomQuery {
    entity: Entity,
    a: &'static mut ComponentA,
}

#[derive(WorldQueryFilter)]
struct QueryFilter {
    _c: With<ComponentC>
}
```
- Replace `Option<With<T>>` with `Has<T>`

```rust
/// old
fn my_system(query: Query<(Entity, Option<With<ComponentA>>)>)
{
  for (entity, has_a_option) in query.iter(){
    let has_a:bool = has_a_option.is_some();
    //todo!()
  }
}

/// new
fn my_system(query: Query<(Entity, Has<ComponentA>)>)
{
  for (entity, has_a) in query.iter(){
    //todo!()
  }
}
```

- Fix queries which had filters in the data position or vice versa.

```rust
// old
fn my_system(query: Query<(Entity, With<ComponentA>)>)
{
  for (entity, _) in query.iter(){
  //todo!()
  }
}

// new
fn my_system(query: Query<Entity, With<ComponentA>>)
{
  for entity in query.iter(){
  //todo!()
  }
}

// old
fn my_system(query: Query<AnyOf<(&ComponentA, With<ComponentB>)>>)
{
  for (entity, _) in query.iter(){
  //todo!()
  }
}

// new
fn my_system(query: Query<Option<&ComponentA>, Or<(With<ComponentA>, With<ComponentB>)>>)
{
  for entity in query.iter(){
  //todo!()
  }
}

```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-11-28 03:56:07 +00:00
..
apply_deferred.rs Fix outdated comment referencing CoreSet (#10294) 2023-10-28 03:18:27 +00:00
component_change_detection.rs Remove useless single tuples and trailing commas (#9720) 2023-09-08 21:46:54 +00:00
custom_query_param.rs Split WorldQuery into WorldQueryData and WorldQueryFilter (#9918) 2023-11-28 03:56:07 +00:00
ecs_guide.rs Allow tuples and single plugins in add_plugins, deprecate add_plugin (#8097) 2023-06-21 20:51:03 +00:00
event.rs Refactor EventReader::iter to read (#9631) 2023-08-30 14:20:03 +00:00
fixed_timestep.rs Unify FixedTime and Time while fixing several problems (#8964) 2023-10-16 01:57:55 +00:00
generic_system.rs Remove OnUpdate system set (#8260) 2023-04-04 00:49:41 +00:00
hierarchy.rs Schedule-First: the new and improved add_systems (#8079) 2023-03-18 01:45:34 +00:00
iter_combinations.rs Unify FixedTime and Time while fixing several problems (#8964) 2023-10-16 01:57:55 +00:00
nondeterministic_system_order.rs Fix non-functional nondeterministic_system_order example (#10719) 2023-11-25 21:13:35 +00:00
one_shot_systems.rs Fix intra-doc link warnings (#10445) 2023-11-08 14:33:46 +00:00
parallel_query.rs Improve execution of examples in CI (#9331) 2023-08-03 12:45:28 +00:00
removal_detection.rs Remove some old references to CoreSet (#9833) 2023-09-18 01:07:11 +00:00
run_conditions.rs Add or_else combinator to run_conditions.rs (#8714) 2023-05-31 16:52:36 +00:00
startup_system.rs Schedule-First: the new and improved add_systems (#8079) 2023-03-18 01:45:34 +00:00
state.rs Add [lints] table, fix adding #![allow(clippy::type_complexity)] everywhere (#10011) 2023-11-18 20:58:48 +00:00
system_closure.rs Allow tuples and single plugins in add_plugins, deprecate add_plugin (#8097) 2023-06-21 20:51:03 +00:00
system_param.rs Schedule-First: the new and improved add_systems (#8079) 2023-03-18 01:45:34 +00:00
system_piping.rs Add system.map(...) for transforming the output of a system (#8526) 2023-08-28 16:36:46 +00:00