From 94c2dedff50b65fea974e5c0a20c5874abfb1b7d Mon Sep 17 00:00:00 2001 From: robtfm <50659922+robtfm@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:10:18 +0000 Subject: [PATCH 1/5] initial --- crates/bevy_app/src/lib.rs | 2 + crates/bevy_app/src/propagate.rs | 554 +++++++++++++++++++++++++++++++ 2 files changed, 556 insertions(+) create mode 100644 crates/bevy_app/src/propagate.rs diff --git a/crates/bevy_app/src/lib.rs b/crates/bevy_app/src/lib.rs index 13021924d033e..de600a51195f4 100644 --- a/crates/bevy_app/src/lib.rs +++ b/crates/bevy_app/src/lib.rs @@ -25,6 +25,7 @@ mod main_schedule; mod panic_handler; mod plugin; mod plugin_group; +mod propagate; mod schedule_runner; mod sub_app; #[cfg(feature = "bevy_tasks")] @@ -37,6 +38,7 @@ pub use main_schedule::*; pub use panic_handler::*; pub use plugin::*; pub use plugin_group::*; +pub use propagate::*; pub use schedule_runner::*; pub use sub_app::*; #[cfg(feature = "bevy_tasks")] diff --git a/crates/bevy_app/src/propagate.rs b/crates/bevy_app/src/propagate.rs new file mode 100644 index 0000000000000..f12ad8a1df05e --- /dev/null +++ b/crates/bevy_app/src/propagate.rs @@ -0,0 +1,554 @@ +use alloc::vec::Vec; +use core::marker::PhantomData; + +use crate::{App, Plugin, Update}; +use bevy_ecs::{ + component::Component, + entity::Entity, + hierarchy::{ChildOf, Children}, + query::{Changed, Or, QueryFilter, With, Without}, + removal_detection::RemovedComponents, + schedule::{IntoSystemConfigs, SystemSet}, + system::{Commands, Local, Query}, +}; + +/// Plugin to automatically propagate a component value to all descendants of entities with +/// a `Propagate` component. +/// +/// The plugin Will maintain the target component over hierarchy changes, adding or removing +/// `C` when a child is added or removed from a tree with a `Propagate::` parent, or if the +/// `Propagate::` component is added, changed or removed. +/// +/// Optionally you can include a query filter `F` to restrict the entities that are updated. +/// Note that the filter is not rechecked dynamically, changes to the filter state will +/// not be picked up until the `Propagate::` component is touched, or the hierarchy +/// is changed. +/// All members of the tree must match the filter for propagation to occur. +/// Individual entities can be skipped or terminate the propagation with the `PropagateOver` +/// and `PropagateStop` components. +pub struct HierarchyPropagatePlugin( + PhantomData (C, F)>, +); + +/// Causes the inner component to be added to this entity and all children. +/// A descendant with a Propagate component of it's own will override propagation +/// from that point in the tree +#[derive(Component, Clone, PartialEq)] +pub struct Propagate(pub C); + +/// Stops the output component being added to this entity. +/// Children will still inherit the component from this entity or its parents +#[derive(Component)] +pub struct PropagateOver(PhantomData C>); + +/// Stops the propagation at this entity. Children will not inherit the component. +#[derive(Component)] +pub struct PropagateStop(PhantomData C>); + +/// The set in which propagation systems are added. You can schedule your logic relative to this set. +#[derive(SystemSet, Clone, PartialEq, PartialOrd, Ord)] +pub struct PropagateSet { + _p: PhantomData C>, +} + +/// Internal struct for managing propagation +#[derive(Component, Clone, PartialEq)] +pub struct Inherited(pub C); + +impl Default for HierarchyPropagatePlugin { + fn default() -> Self { + Self(Default::default()) + } +} + +impl Default for PropagateOver { + fn default() -> Self { + Self(Default::default()) + } +} + +impl Default for PropagateStop { + fn default() -> Self { + Self(Default::default()) + } +} + +impl core::fmt::Debug for PropagateSet { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("PropagateSet") + .field("_p", &self._p) + .finish() + } +} + +impl Eq for PropagateSet {} +impl core::hash::Hash for PropagateSet { + fn hash(&self, state: &mut H) { + self._p.hash(state); + } +} + +impl Default for PropagateSet { + fn default() -> Self { + Self { + _p: Default::default(), + } + } +} + +impl Plugin + for HierarchyPropagatePlugin +{ + fn build(&self, app: &mut App) { + app.add_systems( + Update, + ( + update_source::, + update_stopped::, + update_reparented::, + propagate_inherited::, + propagate_output::, + ) + .chain() + .in_set(PropagateSet::::default()), + ); + } +} + +/// add/remove Inherited and C for entities with a direct Propagate +pub fn update_source( + mut commands: Commands, + changed: Query< + (Entity, &Propagate), + ( + Or<(Changed>, Without>)>, + Without>, + ), + >, + mut removed: RemovedComponents>, +) { + for (entity, source) in &changed { + commands + .entity(entity) + .try_insert(Inherited(source.0.clone())); + } + + for removed in removed.read() { + if let Some(mut commands) = commands.get_entity(removed) { + commands.remove::<(Inherited, C)>(); + } + } +} + +/// remove `Inherited::` and `C` for entities with a `PropagateStop::` +pub fn update_stopped( + mut commands: Commands, + q: Query>, With>, F)>, +) { + for entity in q.iter() { + let mut cmds = commands.entity(entity); + cmds.remove::<(Inherited, C)>(); + } +} + +/// add/remove `Inherited::` and `C` for entities which have changed parent +pub fn update_reparented( + mut commands: Commands, + moved: Query< + (Entity, &ChildOf, Option<&Inherited>), + ( + Changed, + Without>, + Without>, + F, + ), + >, + parents: Query<&Inherited>, + + orphaned: Query< + Entity, + ( + With>, + Without>, + Without, + F, + ), + >, +) { + for (entity, parent, maybe_inherited) in &moved { + if let Ok(inherited) = parents.get(parent.get()) { + commands.entity(entity).try_insert(inherited.clone()); + } else if maybe_inherited.is_some() { + commands.entity(entity).remove::<(Inherited, C)>(); + } + } + + for orphan in &orphaned { + commands.entity(orphan).remove::<(Inherited, C)>(); + } +} + +/// add/remove `Inherited::` for children of entities with modified `Inherited::` +pub fn propagate_inherited( + mut commands: Commands, + changed: Query< + (&Inherited, &Children), + (Changed>, Without>, F), + >, + recurse: Query< + (Option<&Children>, Option<&Inherited>), + (Without>, Without>, F), + >, + mut removed: RemovedComponents>, + mut to_process: Local>)>>, +) { + // gather changed + for (inherited, children) in &changed { + to_process.extend( + children + .iter() + .map(|child| (*child, Some(inherited.clone()))), + ); + } + + // and removed + for entity in removed.read() { + if let Ok((Some(children), _)) = recurse.get(entity) { + to_process.extend(children.iter().map(|child| (*child, None))); + } + } + + // propagate + while let Some((entity, maybe_inherited)) = (*to_process).pop() { + let Ok((maybe_children, maybe_current)) = recurse.get(entity) else { + continue; + }; + + if maybe_current == maybe_inherited.as_ref() { + continue; + } + + if let Some(children) = maybe_children { + to_process.extend( + children + .iter() + .map(|child| (*child, maybe_inherited.clone())), + ); + } + + if let Some(inherited) = maybe_inherited { + commands.entity(entity).try_insert(inherited.clone()); + } else { + commands.entity(entity).remove::<(Inherited, C)>(); + } + } +} + +/// add `C` to entities with `Inherited::` +pub fn propagate_output( + mut commands: Commands, + changed: Query< + (Entity, &Inherited, Option<&C>), + (Changed>, Without>, F), + >, +) { + for (entity, inherited, maybe_current) in &changed { + if maybe_current.is_some_and(|c| &inherited.0 == c) { + continue; + } + + commands.entity(entity).try_insert(inherited.0.clone()); + } +} + +#[cfg(test)] +mod tests { + use bevy_ecs::schedule::Schedule; + + use crate::{App, Update}; + + use super::*; + + #[derive(Component, Clone, PartialEq, Debug)] + struct TestValue(u32); + + #[test] + fn test_simple_propagate() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let intermediate = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagator)) + .id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(intermediate)) + .id(); + + app.update(); + + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_ok()) + } + + #[test] + fn test_reparented() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagator)) + .id(); + + app.update(); + + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_ok()) + } + + #[test] + fn test_reparented_with_prior() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator_a = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let propagator_b = app.world_mut().spawn(Propagate(TestValue(2))).id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagator_a)) + .id(); + + app.update(); + assert_eq!( + app.world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee), + Ok(&TestValue(1)) + ); + app.world_mut() + .commands() + .entity(propagatee) + .insert(ChildOf(propagator_b)); + app.update(); + assert_eq!( + app.world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee), + Ok(&TestValue(2)) + ); + } + + #[test] + fn test_remove_orphan() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagator)) + .id(); + + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_ok()); + app.world_mut() + .commands() + .entity(propagatee) + .remove::(); + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_err()); + } + + #[test] + fn test_remove_propagated() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagator)) + .id(); + + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_ok()); + app.world_mut() + .commands() + .entity(propagator) + .remove::>(); + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_err()); + } + + #[test] + fn test_propagate_over() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let propagate_over = app + .world_mut() + .spawn(TestValue(2)) + .insert(ChildOf(propagator)) + .id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagate_over)) + .id(); + + app.update(); + assert_eq!( + app.world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee), + Ok(&TestValue(1)) + ); + } + + #[test] + fn test_propagate_stop() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let propagate_stop = app + .world_mut() + .spawn(PropagateStop::::default()) + .insert(ChildOf(propagator)) + .id(); + let no_propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagate_stop)) + .id(); + + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), no_propagatee) + .is_err()); + } + + #[test] + fn test_intermediate_override() { + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let intermediate = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagator)) + .id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(intermediate)) + .id(); + + app.update(); + assert_eq!( + app.world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee), + Ok(&TestValue(1)) + ); + + app.world_mut() + .entity_mut(intermediate) + .insert(Propagate(TestValue(2))); + app.update(); + assert_eq!( + app.world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee), + Ok(&TestValue(2)) + ); + } + + #[test] + fn test_filter() { + #[derive(Component)] + struct Marker; + + let mut app = App::new(); + app.add_schedule(Schedule::new(Update)); + app.add_plugins(HierarchyPropagatePlugin::>::default()); + + let propagator = app.world_mut().spawn(Propagate(TestValue(1))).id(); + let propagatee = app + .world_mut() + .spawn_empty() + .insert(ChildOf(propagator)) + .id(); + + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_err()); + + // NOTE: changes to the filter condition are not rechecked + app.world_mut().entity_mut(propagator).insert(Marker); + app.world_mut().entity_mut(propagatee).insert(Marker); + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_err()); + + app.world_mut() + .entity_mut(propagator) + .insert(Propagate(TestValue(1))); + app.update(); + assert!(app + .world_mut() + .query::<&TestValue>() + .get(app.world(), propagatee) + .is_ok()); + } +} From 22707dbb6b6e938c920760256c45820fc679283a Mon Sep 17 00:00:00 2001 From: robtfm <50659922+robtfm@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:24:04 +0000 Subject: [PATCH 2/5] semicolons --- crates/bevy_app/src/propagate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_app/src/propagate.rs b/crates/bevy_app/src/propagate.rs index f12ad8a1df05e..acf65aacc2be5 100644 --- a/crates/bevy_app/src/propagate.rs +++ b/crates/bevy_app/src/propagate.rs @@ -296,7 +296,7 @@ mod tests { .world_mut() .query::<&TestValue>() .get(app.world(), propagatee) - .is_ok()) + .is_ok()); } #[test] @@ -318,7 +318,7 @@ mod tests { .world_mut() .query::<&TestValue>() .get(app.world(), propagatee) - .is_ok()) + .is_ok()); } #[test] From 583c1097948ca28ce6b7232e397fad003ef014fc Mon Sep 17 00:00:00 2001 From: robtfm <50659922+robtfm@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:58:12 +0000 Subject: [PATCH 3/5] backticks --- crates/bevy_app/src/propagate.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_app/src/propagate.rs b/crates/bevy_app/src/propagate.rs index acf65aacc2be5..b8034079b0dc4 100644 --- a/crates/bevy_app/src/propagate.rs +++ b/crates/bevy_app/src/propagate.rs @@ -31,7 +31,7 @@ pub struct HierarchyPropagatePlugin component of it's own will override propagation +/// A descendant with a `Propagate::` component of it's own will override propagation /// from that point in the tree #[derive(Component, Clone, PartialEq)] pub struct Propagate(pub C); @@ -115,7 +115,7 @@ impl Plugin } } -/// add/remove Inherited and C for entities with a direct Propagate +/// add/remove `Inherited::` and `C` for entities with a direct `Propagate::` pub fn update_source( mut commands: Commands, changed: Query< From c04ab3332c75820740e86a3d050d2cc42dd80e61 Mon Sep 17 00:00:00 2001 From: robtfm <50659922+robtfm@users.noreply.github.com> Date: Sun, 1 Jun 2025 23:36:09 +0100 Subject: [PATCH 4/5] generify over R=Relationship --- crates/bevy_app/src/propagate.rs | 107 +++++++++++++++---------------- 1 file changed, 51 insertions(+), 56 deletions(-) diff --git a/crates/bevy_app/src/propagate.rs b/crates/bevy_app/src/propagate.rs index b8034079b0dc4..d4e3d8d0345ca 100644 --- a/crates/bevy_app/src/propagate.rs +++ b/crates/bevy_app/src/propagate.rs @@ -5,39 +5,43 @@ use crate::{App, Plugin, Update}; use bevy_ecs::{ component::Component, entity::Entity, - hierarchy::{ChildOf, Children}, + hierarchy::ChildOf, query::{Changed, Or, QueryFilter, With, Without}, + relationship::{Relationship, RelationshipTarget}, removal_detection::RemovedComponents, - schedule::{IntoSystemConfigs, SystemSet}, + schedule::{IntoScheduleConfigs, SystemSet}, system::{Commands, Local, Query}, }; -/// Plugin to automatically propagate a component value to all descendants of entities with -/// a `Propagate` component. +/// Plugin to automatically propagate a component value to all direct and transient relationship +/// targets (e.g. [`bevy_ecs::hierarchy::Children`]) of entities with a [`Propagate`] component. /// /// The plugin Will maintain the target component over hierarchy changes, adding or removing -/// `C` when a child is added or removed from a tree with a `Propagate::` parent, or if the -/// `Propagate::` component is added, changed or removed. +/// `C` when a relationship `R` (e.g. [`ChildOf`]) is added to or removed from a +/// relationship tree with a [`Propagate`] source, or if the [`Propagate`] component +/// is added, changed or removed. /// /// Optionally you can include a query filter `F` to restrict the entities that are updated. -/// Note that the filter is not rechecked dynamically, changes to the filter state will -/// not be picked up until the `Propagate::` component is touched, or the hierarchy -/// is changed. -/// All members of the tree must match the filter for propagation to occur. -/// Individual entities can be skipped or terminate the propagation with the `PropagateOver` -/// and `PropagateStop` components. -pub struct HierarchyPropagatePlugin( - PhantomData (C, F)>, -); - -/// Causes the inner component to be added to this entity and all children. -/// A descendant with a `Propagate::` component of it's own will override propagation -/// from that point in the tree +/// Note that the filter is not rechecked dynamically: changes to the filter state will not be +/// picked up until the [`Propagate`] component is touched, or the hierarchy is changed. +/// All members of the tree between source and target must match the filter for propagation +/// to reach a given target. +/// Individual entities can be skipped or terminate the propagation with the [`PropagateOver`] +/// and [`PropagateStop`] components. +pub struct HierarchyPropagatePlugin< + C: Component + Clone + PartialEq, + F: QueryFilter = (), + R: Relationship = ChildOf, +>(PhantomData (C, F, R)>); + +/// Causes the inner component to be added to this entity and all direct and transient relationship +/// targets. A target with a [`Propagate`] component of its own will override propagation from +/// that point in the tree. #[derive(Component, Clone, PartialEq)] pub struct Propagate(pub C); /// Stops the output component being added to this entity. -/// Children will still inherit the component from this entity or its parents +/// Relationship targets will still inherit the component from this entity or its parents. #[derive(Component)] pub struct PropagateOver(PhantomData C>); @@ -55,7 +59,7 @@ pub struct PropagateSet { #[derive(Component, Clone, PartialEq)] pub struct Inherited(pub C); -impl Default for HierarchyPropagatePlugin { +impl Default for HierarchyPropagatePlugin { fn default() -> Self { Self(Default::default()) } @@ -96,8 +100,8 @@ impl Default for PropagateSet { } } -impl Plugin - for HierarchyPropagatePlugin +impl Plugin + for HierarchyPropagatePlugin { fn build(&self, app: &mut App) { app.add_systems( @@ -105,8 +109,8 @@ impl Plugin ( update_source::, update_stopped::, - update_reparented::, - propagate_inherited::, + update_reparented::, + propagate_inherited::, propagate_output::, ) .chain() @@ -134,7 +138,7 @@ pub fn update_source( } for removed in removed.read() { - if let Some(mut commands) = commands.get_entity(removed) { + if let Ok(mut commands) = commands.get_entity(removed) { commands.remove::<(Inherited, C)>(); } } @@ -151,32 +155,23 @@ pub fn update_stopped( } } -/// add/remove `Inherited::` and `C` for entities which have changed parent -pub fn update_reparented( +/// add/remove `Inherited::` and `C` for entities which have changed relationship +pub fn update_reparented( mut commands: Commands, moved: Query< - (Entity, &ChildOf, Option<&Inherited>), + (Entity, &R, Option<&Inherited>), ( - Changed, + Changed, Without>, Without>, F, ), >, - parents: Query<&Inherited>, - - orphaned: Query< - Entity, - ( - With>, - Without>, - Without, - F, - ), - >, + relations: Query<&Inherited>, + orphaned: Query>, Without>, Without, F)>, ) { - for (entity, parent, maybe_inherited) in &moved { - if let Ok(inherited) = parents.get(parent.get()) { + for (entity, relation, maybe_inherited) in &moved { + if let Ok(inherited) = relations.get(relation.get()) { commands.entity(entity).try_insert(inherited.clone()); } else if maybe_inherited.is_some() { commands.entity(entity).remove::<(Inherited, C)>(); @@ -188,39 +183,39 @@ pub fn update_reparented( } } -/// add/remove `Inherited::` for children of entities with modified `Inherited::` -pub fn propagate_inherited( +/// add/remove `Inherited::` for targets of entities with modified `Inherited::` +pub fn propagate_inherited( mut commands: Commands, changed: Query< - (&Inherited, &Children), + (&Inherited, &R::RelationshipTarget), (Changed>, Without>, F), >, recurse: Query< - (Option<&Children>, Option<&Inherited>), + (Option<&R::RelationshipTarget>, Option<&Inherited>), (Without>, Without>, F), >, mut removed: RemovedComponents>, mut to_process: Local>)>>, ) { // gather changed - for (inherited, children) in &changed { + for (inherited, targets) in &changed { to_process.extend( - children + targets .iter() - .map(|child| (*child, Some(inherited.clone()))), + .map(|target| (target, Some(inherited.clone()))), ); } // and removed for entity in removed.read() { - if let Ok((Some(children), _)) = recurse.get(entity) { - to_process.extend(children.iter().map(|child| (*child, None))); + if let Ok((Some(targets), _)) = recurse.get(entity) { + to_process.extend(targets.iter().map(|target| (target, None))); } } // propagate while let Some((entity, maybe_inherited)) = (*to_process).pop() { - let Ok((maybe_children, maybe_current)) = recurse.get(entity) else { + let Ok((maybe_targets, maybe_current)) = recurse.get(entity) else { continue; }; @@ -228,11 +223,11 @@ pub fn propagate_inherited( continue; } - if let Some(children) = maybe_children { + if let Some(targets) = maybe_targets { to_process.extend( - children + targets .iter() - .map(|child| (*child, maybe_inherited.clone())), + .map(|target| (target, maybe_inherited.clone())), ); } From e90b5af625f0f6da08539a25647904031b7117c1 Mon Sep 17 00:00:00 2001 From: robtfm <50659922+robtfm@users.noreply.github.com> Date: Sun, 1 Jun 2025 23:39:14 +0100 Subject: [PATCH 5/5] remove a couple of trait bounds --- crates/bevy_app/src/propagate.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/bevy_app/src/propagate.rs b/crates/bevy_app/src/propagate.rs index d4e3d8d0345ca..5d766a626c218 100644 --- a/crates/bevy_app/src/propagate.rs +++ b/crates/bevy_app/src/propagate.rs @@ -43,11 +43,11 @@ pub struct Propagate(pub C); /// Stops the output component being added to this entity. /// Relationship targets will still inherit the component from this entity or its parents. #[derive(Component)] -pub struct PropagateOver(PhantomData C>); +pub struct PropagateOver(PhantomData C>); /// Stops the propagation at this entity. Children will not inherit the component. #[derive(Component)] -pub struct PropagateStop(PhantomData C>); +pub struct PropagateStop(PhantomData C>); /// The set in which propagation systems are added. You can schedule your logic relative to this set. #[derive(SystemSet, Clone, PartialEq, PartialOrd, Ord)] @@ -59,19 +59,21 @@ pub struct PropagateSet { #[derive(Component, Clone, PartialEq)] pub struct Inherited(pub C); -impl Default for HierarchyPropagatePlugin { +impl Default + for HierarchyPropagatePlugin +{ fn default() -> Self { Self(Default::default()) } } -impl Default for PropagateOver { +impl Default for PropagateOver { fn default() -> Self { Self(Default::default()) } } -impl Default for PropagateStop { +impl Default for PropagateStop { fn default() -> Self { Self(Default::default()) }