bevyengine / bevyengine/bevy

Runtime Predicate Query Filters

Open
#18,166 0 comments 2 reactions 0 assignees View on GitHub
A-ECS C-Feature D-Modest X-Needs-SME
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

Bevy's `QueryFilter` is good at enforcing compile time checks on queries. Users can then filter queries at runtime as so:

```rust
#[derive(Component)]
struct A(usize);

#[derive(Component)]
struct B;

fn system(q_a: Query<&A, With>) {
for a in q_a.iter().filter(|a| a.0 < 5) {
// only do things if a is < 5!
}
}
```

This works great for systems scheduled to run once a frame - logic is close together, and oftentimes you're working with at most a couple queries at a time. Any more and things become hard to work with and you're better splitting things apart into different systems.

When designing complex things with exclusive world access using the `QueryBuilder` API you can find yourself building queries and using them throughout your code. You may call the same query from different locations in your code (and are often querying singular entities). Due to the linear nature of working with exclusive world access the query construction site and call site can be quite far apart (or even abstracted over completely).

I feel like `QueryBuilder` can benefit from runtime predicate query filters - allowing us to declaratively express all constraints on the type of entity we want to match up front.

Possible API:
```rust
let mut world = World::default();

let e1 = world.spawn((A(2), B));
let e2 = world.spawn((A(6), B));

let q = QueryBuilder::new()
.with::()
.predicate_filter(|a: &a| a.0 < 5)
.build();

// q can be used anywhere and only returns entities whose `A` is less than 5!
```

# Concerns

Arbitrary predicate filters can mess with determinism - we can't enforce the filter is deterministic. IMO this makes sense if this is used in a regular system, but less so if we're working with exclusive world access - any unintentional non-determinism is a logic error. Additionally, non-determinism can be desirable - if you're procedurally generating the world of your game, you're likely working with long-term exclusive world access, and intentional randomness in the matching filter can be a choice made for variety.

# Implementation Attempt

I tried extending the current `QueryFilter` - I wasn't able to extend the current implementation easily without changing API signatures.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.