-
Notifications
You must be signed in to change notification settings - Fork 17
Bevy 0.13 Update PR #55
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
Conversation
Authored-by: RobWalt <[email protected]>
- change `ReadOnlyWoldQuery` to `ReadOnlyQueryData` - additionally implement `QueryData` - change the impls for `WorldQuery` - add a new method on the `TraitQueryState` to get it from the world Authored-by: RobWalt <[email protected]>
Authored-by: Robert Walter <[email protected]>
- tests fail completely Authored-by: RobWalt <[email protected]>
I tried looking deeper into the failing tests and here's a short analysis of the Here's the relevant test code: use super::*;
use bevy_ecs::prelude::*;
use std::fmt::{Debug, Display};
// Required for proc macros.
use crate as bevy_trait_query;
#[derive(Resource, Default)]
pub struct Output(Vec<String>);
#[queryable]
pub trait Person {
fn name(&self) -> &str;
fn age(&self) -> u32;
fn set_age(&mut self, age: u32);
}
#[derive(Component)]
struct Fem;
#[derive(Component)]
pub struct Human(String, u32);
impl Person for Human {
fn name(&self) -> &str {
&self.0
}
fn age(&self) -> u32 {
self.1
}
fn set_age(&mut self, age: u32) {
self.1 = age;
}
}
#[derive(Component)]
pub struct Dolphin(u32);
impl Person for Dolphin {
fn name(&self) -> &str {
"Reginald"
}
fn age(&self) -> u32 {
self.0
}
fn set_age(&mut self, age: u32) {
self.0 = age;
}
}
#[test]
fn all1() {
let mut world = World::new();
world.init_resource::<Output>();
world
.register_component_as::<dyn Person, Human>()
.register_component_as::<dyn Person, Dolphin>();
world.spawn(Human("Henry".to_owned(), 22));
world.spawn((Human("Eliza".to_owned(), 31), Fem, Dolphin(6)));
world.spawn((Human("Garbanzo".to_owned(), 17), Fem, Dolphin(17)));
world.spawn(Dolphin(27));
let mut schedule = Schedule::default();
schedule.add_systems((print_all_info, (age_up_fem, age_up_not)).chain());
schedule.run(&mut world);
schedule.run(&mut world);
assert_eq!(
world.resource::<Output>().0,
&[
"All people:",
"Henry: 22",
"Eliza: 31",
"Reginald: 6",
"Garbanzo: 17",
"Reginald: 17",
"Reginald: 27",
"",
"All people:",
"Henry: 23",
"Eliza: 32",
"Reginald: 7",
"Garbanzo: 18",
"Reginald: 18",
"Reginald: 28",
"",
]
);
}
// Prints the name and age of every `Person`.
fn print_all_info(people: Query<&dyn Person>, mut output: ResMut<Output>) {
output.0.push("All people:".to_string());
for all in &people {
for person in all {
output
.0
.push(format!("{}: {}", person.name(), person.age()));
}
}
output.0.push(Default::default());
}
fn age_up_fem(mut q: Query<&mut dyn Person, With<Fem>>) {
for all in &mut q {
for mut p in all {
let age = p.age();
p.set_age(age + 1);
}
}
}
fn age_up_not(mut q: Query<&mut dyn Person, Without<Fem>>) {
for all in &mut q {
for mut p in all {
let age = p.age();
p.set_age(age + 1);
}
}
} The results of the test are:
If we look closer at the results, it seems like the query only iterates over the entities which have two entities which implement the trait. Actually it seems like it iterates only over entities which have all of the components which implement the trait. Let's quickly verify that. I added: #[derive(Component)]
pub struct Alien(u32);
impl Person for Alien {
fn name(&self) -> &str {
"Goobert"
}
fn age(&self) -> u32 {
self.0
}
fn set_age(&mut self, age: u32) {
self.0 = age;
}
}
...
world
.register_component_as::<dyn Person, Human>()
.register_component_as::<dyn Person, Alien>()
.register_component_as::<dyn Person, Dolphin>();
world.spawn(Human("Henry".to_owned(), 22));
world.spawn(Alien(222));
world.spawn((Human("Eliza".to_owned(), 31), Fem, Dolphin(6), Alien(100)));
world.spawn((Human("Garbanzo".to_owned(), 17), Fem, Dolphin(17)));
world.spawn(Dolphin(27));
... And the test result reports
So that might be true. |
…nlyQueryData for One<&'a mut T>
Authored-by: RobWalt <[email protected]>
Authored-by: RobWalt <[email protected]>
Big shoutout and credit to @Azorlogh for helping me out here! |
@@ -95,7 +101,7 @@ unsafe impl<'a, Trait: ?Sized + TraitQuery> WorldQuery for One<&'a Trait> { | |||
} | |||
|
|||
const IS_DENSE: bool = false; | |||
const IS_ARCHETYPAL: bool = false; | |||
// const IS_ARCHETYPAL: bool = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover comment
Authored-by: RobWalt <[email protected]> Reviewed-by: Azorlogh <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same fix should also apply here.
…ssues Authored-by: RobWalt <[email protected]> Reviewed-by: SkiFire13
Authored-by: RobWalt <[email protected]>
@SkiFire13 First: Thanks for the review! I'm still not quiet sure what the |
Authored-by: RobWalt <[email protected]> Reviewed-by: Azorlogh <[email protected]>
Thanks for updating this guys :) |
Need any help with getting this one wrapped up? |
I have not had a close look at the code, but I have played around with this PR and haven't found any issues so far. I tried both a system-based query and a world query ( |
One question that just popped up for us is:
Previously you could use it in the filter position, now it doesn't work anymore. It might be misleading to have it work in both positions, so maybe another struct
|
339f718
to
e071c3d
Compare
Authored-by: RobWalt <[email protected]>
FYI: PR seems to be unaffected by 0.13.1 - the tests are still green |
FWIW, I've been using this PR in my project for a few weeks and it works great. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies for the delay on this, I've been busy with IRL stuff. I'll try to get this merged in soon
if not_first { | ||
let mut intermediate = access.clone(); | ||
intermediate.add_read(component); | ||
new_access.append_or(&intermediate); | ||
new_access.extend_access(&intermediate); | ||
} else { | ||
new_access.and_with(component); | ||
new_access.access_mut().add_read(component); | ||
not_first = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of the new_access
and intermediate
variables? Can we not insert directly into the filtered access?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This similar to how AnyOf
is implemented in Bevy. The expected result of the whole method is that access
contains the result of (access AND write component1) OR (access AND write component2) OR ...
The way this is achieved is by computing each access AND write componentN
in an intermediate
FilteredAccess
, and then OR
them together in an accumulator, which is new_access
FilteredAccess
. new_access
needs to be different from access
because to compute each intermediate you need the original access
, so directly modifying access
will produce incorrect results.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, thank you for explaining.
Ready for review ✅
The PR is in a review-ready state now. All tests are green and we get now compile errors.
Irrelevant and superseded by the section above now, just leaving this first version of the description for transparency
This is most probably a very naive try to update this crate to bevy 0.13. The main things that I changed were:
ReadOnlyWorldQuery
impl intoQueryData
+ReadOnlyQueryData
implsQueryFilter
impls forOneAdded
andOneChanged
get_state
method on theWorldQuery
implget_state
change includes adding a newget
method forTraitQueryState
which mostly follows theinit
methodMost of these adjustments are super naive. I tried to mirror existing code as closely as possible (e.g. I consulted the bevy main repo for the trait impls). Most notably:
update_archetype_component_access
in bevy 0.13I'm happy to continue working on this update (and also future update) but I'm afraid I need a bit of mentoring as I'm stuck now
Related to #54