Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 32 additions & 22 deletions crates/bevy_app/src/propagate.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use alloc::vec::Vec;
use core::marker::PhantomData;

use crate::{App, Plugin, Update};
use crate::{App, Plugin};
#[cfg(feature = "bevy_reflect")]
use bevy_ecs::reflect::ReflectComponent;
use bevy_ecs::{
component::Component,
entity::Entity,
hierarchy::ChildOf,
intern::Interned,
lifecycle::RemovedComponents,
query::{Changed, Or, QueryFilter, With, Without},
relationship::{Relationship, RelationshipTarget},
schedule::{IntoScheduleConfigs, SystemSet},
schedule::{IntoScheduleConfigs, ScheduleLabel, SystemSet},
system::{Commands, Local, Query},
};
#[cfg(feature = "bevy_reflect")]
Expand All @@ -33,15 +34,30 @@ use bevy_reflect::Reflect;
/// Individual entities can be skipped or terminate the propagation with the [`PropagateOver`]
/// and [`PropagateStop`] components.
///
/// Propagation occurs during [`Update`] in the [`PropagateSet<C>`] system set.
/// The schedule can be configured via [`HierarchyPropagatePlugin::new`].
/// You should be sure to schedule your logic relative to this set: making changes
/// that modify component values before this logic, and reading the propagated
/// values after it.
pub struct HierarchyPropagatePlugin<
C: Component + Clone + PartialEq,
F: QueryFilter = (),
R: Relationship = ChildOf,
>(PhantomData<fn() -> (C, F, R)>);
> {
schedule: Interned<dyn ScheduleLabel>,
_marker: PhantomData<fn() -> (C, F, R)>,
}

impl<C: Component + Clone + PartialEq, F: QueryFilter, R: Relationship>
HierarchyPropagatePlugin<C, F, R>
{
/// Construct the plugin. The propagation systems will be placed in the specified schedule.
pub fn new(schedule: impl ScheduleLabel) -> Self {
Self {
schedule: schedule.intern(),
_marker: PhantomData,
}
}
}

/// Causes the inner component to be added to this entity and all direct and transient relationship
/// targets. A target with a [`Propagate<C>`] component of its own will override propagation from
Expand Down Expand Up @@ -80,14 +96,6 @@ pub struct PropagateSet<C: Component + Clone + PartialEq> {
)]
pub struct Inherited<C: Component + Clone + PartialEq>(pub C);

impl<C: Component + Clone + PartialEq, F: QueryFilter, R: Relationship> Default
for HierarchyPropagatePlugin<C, F, R>
{
fn default() -> Self {
Self(Default::default())
}
}

impl<C> Default for PropagateOver<C> {
fn default() -> Self {
Self(Default::default())
Expand Down Expand Up @@ -129,7 +137,7 @@ impl<C: Component + Clone + PartialEq, F: QueryFilter + 'static, R: Relationship
{
fn build(&self, app: &mut App) {
app.add_systems(
Update,
self.schedule,
(
update_source::<C, F>,
update_stopped::<C, F>,
Expand Down Expand Up @@ -295,7 +303,7 @@ mod tests {
fn test_simple_propagate() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let intermediate = app
Expand All @@ -322,7 +330,7 @@ mod tests {
fn test_reparented() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let propagatee = app
Expand All @@ -344,7 +352,7 @@ mod tests {
fn test_reparented_with_prior() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator_a = app.world_mut().spawn(Propagate(TestValue(1))).id();
let propagator_b = app.world_mut().spawn(Propagate(TestValue(2))).id();
Expand Down Expand Up @@ -378,7 +386,7 @@ mod tests {
fn test_remove_orphan() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let propagatee = app
Expand Down Expand Up @@ -409,7 +417,7 @@ mod tests {
fn test_remove_propagated() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let propagatee = app
Expand Down Expand Up @@ -440,7 +448,7 @@ mod tests {
fn test_propagate_over() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let propagate_over = app
Expand All @@ -467,7 +475,7 @@ mod tests {
fn test_propagate_stop() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let propagate_stop = app
Expand All @@ -493,7 +501,7 @@ mod tests {
fn test_intermediate_override() {
let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue>::new(Update));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let intermediate = app
Expand Down Expand Up @@ -534,7 +542,9 @@ mod tests {

let mut app = App::new();
app.add_schedule(Schedule::new(Update));
app.add_plugins(HierarchyPropagatePlugin::<TestValue, With<Marker>>::default());
app.add_plugins(HierarchyPropagatePlugin::<TestValue, With<Marker>>::new(
Update,
));

let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id();
let propagatee = app
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_feathers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
//! Please report issues, submit fixes and propose changes.
//! Thanks for stress-testing; let's build something better together.

use bevy_app::{HierarchyPropagatePlugin, Plugin, PostUpdate};
use bevy_app::{HierarchyPropagatePlugin, Plugin, PostUpdate, Update};
use bevy_asset::embedded_asset;
use bevy_ecs::query::With;
use bevy_text::{TextColor, TextFont};
Expand Down Expand Up @@ -63,8 +63,8 @@ impl Plugin for FeathersPlugin {
app.add_plugins((
ControlsPlugin,
CursorIconPlugin,
HierarchyPropagatePlugin::<TextColor, With<ThemedText>>::default(),
HierarchyPropagatePlugin::<TextFont, With<ThemedText>>::default(),
HierarchyPropagatePlugin::<TextColor, With<ThemedText>>::new(Update),
HierarchyPropagatePlugin::<TextFont, With<ThemedText>>::new(Update),
UiMaterialPlugin::<AlphaPatternMaterial>::default(),
));

Expand Down
Loading