-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Ensure required components are consistently depth-first #20110
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
Ensure required components are consistently depth-first #20110
Conversation
5362a26
to
8b14b9c
Compare
8b14b9c
to
18c4ca4
Compare
@SkiFire13 is this ready for review now that the bundle-split PR is merged? This is still in draft mode :) |
Ah yes, I was forgetting to change the status! I think it might still need some more tests, but the implementation should be ready. |
I encountered an issue where a required component is not registered at all on I try to review this the next days and if needed suggest another test if this is missing. |
I added a few more tests, cleaned up some parts of the code and added a fix for #20173 (I would have preferred a separate PR but that ended up being requiring too many changes that would be included in this PR anyway) |
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.
First pass, haven't looked in depth at required.rs
let explicit_components_len = component_ids.len(); | ||
let mut required_components = RequiredComponents::default(); | ||
for component_id in component_ids.iter().copied() { | ||
let mut depth_first_components = IndexMap::<_, _, FixedHasher>::default(); |
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.
If i understand correctly there could be 2 meanings to DFS:
- if we add two components A and B at the same time in a bundle and they both required C, we want to add the version required by A because it appears first in the bundle list. This is the DFS performed here
- if A requires B and C, and both B and C require D, we want to add the version required by B first because it appears first in the required list. This is handled somewhere else, probably at registration time (I have yet to review that)
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.
Yes. A way in which you can unify these two views is seeing a bundle as if it was directly requiring all its components, with the "default" value the one in the actual bundle.
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.
Looks good! The comments were extremely helpful in understanding some of the tricky parts, especially the step-by-step comments in register_required_components
! I left some nits on things that tripped me up while I was reading it, but none of them should be blocking.
Entity, | ||
MaybeLocation, | ||
); | ||
// If already registered as a direct required component then bail. |
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.
Why ignore the new constructor instead of updating the registration? It looks like the old code did an update in this case.
Or, is this an error case and we should panic!
or return an Err
somehow?
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 old code used to decide based on the given inheritance_depth
. If we go by the new rules the second occurence of a duplicated direct required components would always "lose" to the first and hence be ignored, though I can see why this is not ideal. I'll try to see if we can update this to return a Result
and/or panic (possibly with a try_
variant of the methods).
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.
I changed this to panic for now. I'm not particularly a fan, but it's a bit awkward to return a RequiredComponentsError
. Let me know what you (and others) think.
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.
I'm fine with the decision to panic for now: this PR is already very involved.
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 is very complex, but extremely well-commented and has a robust set of tests. In the course of reviewing I've been convinced that this is the correct behavior, and I'm very happy to remove inheritance_depth.
Thanks for taking the time to do this well.
…0110) # Objective - Fixes bevyengine#19863 by removing `inheritance_depth` - Fixed bevyengine#19333 by properly using depth-first order priority - Helps with bevyengine#19300 (not sure if it could be closed with this PR) - Fixes bevyengine#20173 - Overall, fix the weird situation that required components are in, where some operations respect a depth-first order priority while other respect a breadth-first order priority. ## Solution - Switch everything to a depth-first order priority as @cart originally intended it. - Effectively revert bevyengine#18028, which tried to give priority to components with higher inheritance depth (i.e. with a breadth-first order priority). ## Testing Most existing tests pass, except a couple that were removed due to testing inheritance depth or the breadth-first order priority that this PR will remove. Some tests were also added, some of which as regression tests and others to add more coverage.
Objective
RequiredComponent.inheritance_depth
docs do not matchComponent
derive impl #19863 by removinginheritance_depth
Component::register_required_components
can be implemented in an unsound way #20173Solution
Testing
Most existing tests pass, except a couple that were removed due to testing inheritance depth or the breadth-first order priority that this PR will remove.
Some tests were also added, some of which as regression tests and others to add more coverage.