-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Add component change detection conditions #9746
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
`any_component_changed` and `any_component_changed_or_removed`
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 think that we should be able to specify this for T: WorldQuery, which would make this quite a bit more powerful.
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.
It would be helpful to have a variant that checks for changed but not added components. We don't have this variant for Mut
or Ref
since it's easy enough to do val.is_changed() && !val.is_added()
, but it's less convenient to add a custom run condition that checks this.
@alice-i-cecile I tried making this change and am getting this monster of an error:
|
The problem is 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.
Right, I can see why that change failed. I do think an added
variant would be nice here, but it doesn't have to be this PR.
Also fixed doc comment
// NOTE: The check for removed components must come before the check for changed compoents. | ||
// If `query.is_empty()` is called first, then the short-circuiting behavior means that the removed | ||
// components buffer may not be consumed every frame. | ||
any_component_removed::<T>().or_else(any_component_changed::<T>()) |
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.
It doesn't really matter, but I'd like to comment that using the or_else
combinator has slightly more overhead than just doing removals.iter().count() != 0 || !changed.is_empty()
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 was previously attempted to be added in #7711, which was marked controversial for the same comments I'm adding below.
@@ -946,6 +946,31 @@ pub mod common_conditions { | |||
move |mut removals: RemovedComponents<T>| removals.iter().count() != 0 | |||
} | |||
|
|||
/// Generates a [`Condition`](super::Condition)-satisfying closure that | |||
/// returns `true` if there are any entities with a component of the given | |||
/// type changed. Newly added components are considered changed. |
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 runs a potentially very expensive query (iterating through all instances of component T) single-threaded and inline in the scheduler. This blocks the scheduler from launching other systems and can be a very big performance footgun, particularly when there are a large number of entities in the world with T. At a minimum, this should be noted in the doc comments, and it should recommend directly using change detection in the system as the recommenced alternative.
|
||
/// Generates a [`Condition`] that returns `true` if there are any entities | ||
/// with a component of the given type changed or removed. Newly added | ||
/// components are considered changed. |
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.
Similar performance footgun concerns here.
|
||
/// Generates a [`Condition`](super::Condition)-satisfying closure that | ||
/// returns `true` if there are any entities with a component of the given | ||
/// type that were just added. |
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.
Similar performance footgun concerns here.
@james7132 makes a really good point. I don't think it makes sense to add this to bevy with the current performance drawbacks. Checking for changes within the system is more performant, and not much worse ergonomics. If in the future we track this kind of stuff directly, then these conditions would be nice. Closing this PR |
Since this is the second time a PR like this was opened, would it be reasonable to leave a comment in the source code explaining why these functions are missing? |
Added
any_component_changed
andany_component_changed_or_removed
Objective
I believe these conditions are generally useful, and having them built in makes sense. Also makes it more symmetric with the resource conditions
Solution
Added them to the
common_conditions
moduleChangelog
Added
any_component_changed
,any_component_changed_or_removed
andany_component_added
run conditions