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

Query filter for component value rather than component existence #5639

Open
ItsDoot opened this issue Aug 9, 2022 · 5 comments
Open

Query filter for component value rather than component existence #5639

ItsDoot opened this issue Aug 9, 2022 · 5 comments
Labels
A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible D-Complex Quite challenging from either a design or technical perspective. Ask for help! X-Controversial There is active debate or serious implications around merging this PR

Comments

@ItsDoot
Copy link
Contributor

ItsDoot commented Aug 9, 2022

What problem does this solve or what need does it fill?

I'm working on a game that uses a lot of different 'status effects'. These status effects are presently implemented on each character as an inserted/removed component, but I am interested in exploring these with always-inserted bool fields instead (akin to Visibility). The main issue I have is that I won't be able to filter out entities as easily as I can presently (like finding all poisoned entities by using With<Poisoned>).

What solution would you like?

UPDATE: Working proof of concept: https://crates.io/crates/bevy_mod_check_filter

A Query Filter pair akin to With/Without, that instead of checking for component existence, checks for component value. Given we don't have full const generics yet, this should probably be limited to true/false for simplicity. Alternatively, the current value could be compared to the Default value.

The name for these filters? Unsure. Maybe Truthy/Falsey or Enabled/Disabled?

Illustration

Today:

#[derive(Component)]
struct Poisoned;
fn all_poisoned(entities: Query<&Name, With<Poisoned>>) {
    // ...
}

New query filter (see how we don't lose the ergonomics of marker components?):

#[derive(Component)]
struct Poisoned(bool);
// We will need some machinery like Deref or Into to extract the current value, but I'll leave that for discussion.
fn all_poisoned(entities: Query<&Name, Enabled<Poisoned>>) {
}

What alternative(s) have you considered?

Filtering the way that the Visibility struct does presently. It's not the best ergonomics, though.

Additional context

Related to the discussion found in #3796.

@ItsDoot ItsDoot added C-Feature A new feature, making something new possible S-Needs-Triage This issue needs to be labelled labels Aug 9, 2022
@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events X-Controversial There is active debate or serious implications around merging this PR and removed S-Needs-Triage This issue needs to be labelled labels Aug 9, 2022
@alice-i-cecile
Copy link
Member

This is a special case of #4513 with nice syntax. rust-lang/rfcs#2593 or similar would allow us to encode this information directly in the type system, but doesn't seem likely to ever land in Rust.

We may be able to use const generics to avoid special-casing true/false style enums and create a special Variant query filter.

@ItsDoot
Copy link
Contributor Author

ItsDoot commented Aug 9, 2022

This is a special case of #4513 with nice syntax.

Ah, I hadn't considered indexes as an alternative! Regardless, I think the idea proposed here is worth looking into as a stopgap, given it likely requires much less work.

@ItsDoot
Copy link
Contributor Author

ItsDoot commented Aug 9, 2022

We may be able to use const generics to avoid special-casing true/false style enums and create a special Variant query filter.

I put together a rough sketch of what this could look like: https://gist.github.com/ItsDoot/c6a6289749963b81b3dc57b6cb559eb0

@ItsDoot
Copy link
Contributor Author

ItsDoot commented Aug 10, 2022

I have taken the liberty of making a PoC: https://crates.io/crates/bevy_mod_check_filter

And... it works! So far at least. 🙂

@alice-i-cecile alice-i-cecile added the D-Complex Quite challenging from either a design or technical perspective. Ask for help! label Feb 14, 2023
@TheNeikos
Copy link
Contributor

Before we get const generics for everything, this could still work for 'simple' enums.

For example member-less enums can have their discriminant's compared without much fanfare (https://doc.rust-lang.org/stable/std/mem/fn.discriminant.html is const-stable since 1.75!)

Another option is to use hashing to turn a const value into an integer, and then use that to query/filter stuff.

Since macros have been allowed in type level for some time, this could work! (Even if only as a community crate for now)

So for example Query<&Player, WithValue![Status::Stunned]> would be a possibility. It then expands to Query<&Player, WithValue<V = { const_hash(Status::Stunned) }>. Where const_hash is some form of constant hashing (either rust-lang/rust#104061 gets solved, or one uses something like https://docs.rs/const-fnv1a-hash/latest/const_fnv1a_hash/).

I don't know though if bevy has a good way to query stuff by value internally? Or if one would have to do that ad-hoc. Although I don't know at all actually how Query works under the hood haha

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-Complex Quite challenging from either a design or technical perspective. Ask for help! X-Controversial There is active debate or serious implications around merging this PR
Projects
None yet
Development

No branches or pull requests

3 participants