Attempt to remove component from render world if not extracted. (#15904)

# Objective

Ensure that components that are conditionally extracted do not linger in
the render world when not extracted from the main world.

## Solution

If the `ExtractComponent` returns `None`, we'll remove the render world
component. I think this is the most sensible behavior here. In the
future if there really is a use case for keeping the previous render
component around, we could add a `Option<Self::Out>` parameter for the
previous render component to the method, or something similar. I think
that this follows the principle of least surprise here relative to what
`None` would suggest and the way that render nodes are typically
written. The alternative would be to add an `enabled` field to pretty
much every camera settings component, or duplicate the extraction
condition as #15856 does.

## Testing

`transmission` no longer crashes.

## Migration Guide

Components that implement `ExtractComponent` and return `None` will
cause the extracted component to be removed from the render world.
This commit is contained in:
charlotte 2024-10-14 21:21:53 -07:00 committed by GitHub
parent c1bb4b255d
commit acbed6040e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -42,9 +42,10 @@ pub trait ExtractComponent: Component {
/// The output from extraction. /// The output from extraction.
/// ///
/// Returning `None` based on the queried item can allow early optimization, /// Returning `None` based on the queried item will remove the component from the entity in
/// for example if there is an `enabled: bool` field on `Self`, or by only accepting /// the render world. This can be used, for example, to conditionally extract camera settings
/// values within certain thresholds. /// in order to disable a rendering feature on the basis of those settings, without removing
/// the component from the entity in the main world.
/// ///
/// The output may be different from the queried component. /// The output may be different from the queried component.
/// This can be useful for example if only a subset of the fields are useful /// This can be useful for example if only a subset of the fields are useful
@ -205,6 +206,8 @@ fn extract_components<C: ExtractComponent>(
for (entity, query_item) in &query { for (entity, query_item) in &query {
if let Some(component) = C::extract_component(query_item) { if let Some(component) = C::extract_component(query_item) {
values.push((entity, component)); values.push((entity, component));
} else {
commands.entity(entity).remove::<C>();
} }
} }
*previous_len = values.len(); *previous_len = values.len();
@ -222,6 +225,8 @@ fn extract_visible_components<C: ExtractComponent>(
if view_visibility.get() { if view_visibility.get() {
if let Some(component) = C::extract_component(query_item) { if let Some(component) = C::extract_component(query_item) {
values.push((entity, component)); values.push((entity, component));
} else {
commands.entity(entity).remove::<C>();
} }
} }
} }