mirror of
https://github.com/bevyengine/bevy
synced 2025-01-08 03:08:55 +00:00
2d1b4939d2
# Objective Fixes #15560 Fixes (most of) #15570 Currently a lot of examples (and presumably some user code) depend on toggling certain render features by adding/removing a single component to an entity, e.g. `SpotLight` to toggle a light. Because of the retained render world this no longer works: Extract will add any new components, but when it is removed the entity persists unchanged in the render world. ## Solution Add `SyncComponentPlugin<C: Component>` that registers `SyncToRenderWorld` as a required component for `C`, and adds a component hook that will clear all components from the render world entity when `C` is removed. We add this plugin to `ExtractComponentPlugin` which fixes most instances of the problem. For custom extraction logic we can manually add `SyncComponentPlugin` for that component. We also rename `WorldSyncPlugin` to `SyncWorldPlugin` so we start a naming convention like all the `Extract` plugins. In this PR I also fixed a bunch of breakage related to the retained render world, stemming from old code that assumed that `Entity` would be the same in both worlds. I found that using the `RenderEntity` wrapper instead of `Entity` in data structures when referring to render world entities makes intent much clearer, so I propose we make this an official pattern. ## Testing Run examples like ``` cargo run --features pbr_multi_layer_material_textures --example clearcoat cargo run --example volumetric_fog ``` and see that they work, and that toggles work correctly. But really we should test every single example, as we might not even have caught all the breakage yet. --- ## Migration Guide The retained render world notes should be updated to explain this edge case and `SyncComponentPlugin` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Trashtalk217 <trashtalk217@gmail.com>
42 lines
1.7 KiB
Rust
42 lines
1.7 KiB
Rust
use core::marker::PhantomData;
|
|
|
|
use bevy_app::{App, Plugin};
|
|
use bevy_ecs::component::Component;
|
|
|
|
use crate::sync_world::{EntityRecord, PendingSyncEntity, SyncToRenderWorld};
|
|
|
|
/// Plugin that registers a component for automatic sync to the render world. See [`SyncWorldPlugin`] for more information.
|
|
///
|
|
/// This plugin is automatically added by [`ExtractComponentPlugin`], and only needs to be added for manual extraction implementations.
|
|
///
|
|
/// # Implementation details
|
|
///
|
|
/// It adds [`SyncToRenderWorld`] as a required component to make the [`SyncWorldPlugin`] aware of the component, and
|
|
/// handles cleanup of the component in the render world when it is removed from an entity.
|
|
///
|
|
/// # Warning
|
|
/// When the component is removed from the main world entity, all components are removed from the entity in the render world.
|
|
/// This is done in order to handle components with custom extraction logic and derived state.
|
|
///
|
|
/// [`ExtractComponentPlugin`]: crate::extract_component::ExtractComponentPlugin
|
|
/// [`SyncWorldPlugin`]: crate::sync_world::SyncWorldPlugin
|
|
pub struct SyncComponentPlugin<C: Component>(PhantomData<C>);
|
|
|
|
impl<C: Component> Default for SyncComponentPlugin<C> {
|
|
fn default() -> Self {
|
|
Self(PhantomData)
|
|
}
|
|
}
|
|
|
|
impl<C: Component> Plugin for SyncComponentPlugin<C> {
|
|
fn build(&self, app: &mut App) {
|
|
app.register_required_components::<C, SyncToRenderWorld>();
|
|
|
|
app.world_mut().register_component_hooks::<C>().on_remove(
|
|
|mut world, entity, _component_id| {
|
|
let mut pending = world.resource_mut::<PendingSyncEntity>();
|
|
pending.push(EntityRecord::ComponentRemoved(entity));
|
|
},
|
|
);
|
|
}
|
|
}
|