Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime Predicate Query Filters #18166

Open
dmyyy opened this issue Mar 5, 2025 · 0 comments
Open

Runtime Predicate Query Filters #18166

dmyyy opened this issue Mar 5, 2025 · 0 comments
Labels
A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes X-Controversial There is active debate or serious implications around merging this PR

Comments

@dmyyy
Copy link
Contributor

dmyyy commented Mar 5, 2025

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

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

#[derive(Component)]
struct B;

fn system(q_a: Query<&A, With<B>>) {
    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:

let mut world = World::default();

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

let q = QueryBuilder::new()
    .with::<B>()
    .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.

@dmyyy dmyyy added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Mar 5, 2025
@dmyyy dmyyy changed the title Runtime Predicate Query Filter Runtime Predicate Query Filters Mar 5, 2025
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events X-Contentious There are nontrivial implications that should be thought through D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes X-Controversial There is active debate or serious implications around merging this PR and removed S-Needs-Triage This issue needs to be labelled X-Contentious There are nontrivial implications that should be thought through labels Mar 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes X-Controversial There is active debate or serious implications around merging this PR
Projects
None yet
Development

No branches or pull requests

2 participants