diff --git a/crates/bevy_dev_tools/src/fps_overlay.rs b/crates/bevy_dev_tools/src/fps_overlay.rs index d3f57f9984..069882cb4e 100644 --- a/crates/bevy_dev_tools/src/fps_overlay.rs +++ b/crates/bevy_dev_tools/src/fps_overlay.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ schedule::{common_conditions::resource_changed, IntoSystemConfigs}, system::{Commands, Query, Res, Resource}, }; -use bevy_hierarchy::BuildChildren; +use bevy_hierarchy::{BuildChildren, ChildBuild}; use bevy_text::{Font, Text, TextSection, TextStyle}; use bevy_ui::{ node_bundles::{NodeBundle, TextBundle}, diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 8ca6b63e26..3cc563d502 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -13,7 +13,7 @@ use bevy_core::Name; use bevy_core_pipeline::prelude::Camera3dBundle; use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{entity::Entity, world::World}; -use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder}; +use bevy_hierarchy::{BuildChildren, ChildBuild, WorldChildBuilder}; use bevy_math::{Affine2, Mat4, Vec3}; use bevy_pbr::{ DirectionalLight, DirectionalLightBundle, PbrBundle, PointLight, PointLightBundle, SpotLight, diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index 6c32979666..b8f067d83d 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -261,7 +261,7 @@ impl Command for RemoveParent { /// ``` /// # use bevy_ecs::bundle::Bundle; /// # use bevy_ecs::system::Commands; -/// # use bevy_hierarchy::BuildChildren; +/// # use bevy_hierarchy::{ChildBuild, BuildChildren}; /// # #[derive(Bundle)] /// # struct MyBundle {} /// # #[derive(Bundle)] @@ -279,30 +279,55 @@ pub struct ChildBuilder<'a> { push_children: PushChildren, } -impl ChildBuilder<'_> { +/// Trait for building children entities and adding them to a parent entity. This is used in +/// implementations of [`BuildChildren`] as a bound on the [`Builder`](BuildChildren::Builder) +/// associated type. The closure passed to [`BuildChildren::with_children`] accepts an +/// implementation of `ChildBuild` so that children can be spawned via [`ChildBuild::spawn`]. +pub trait ChildBuild { + /// Spawn output type. Both [`spawn`](Self::spawn) and [`spawn_empty`](Self::spawn_empty) return + /// an implementation of this type so that children can be operated on via method-chaining. + /// Implementations of `ChildBuild` reborrow `self` when spawning entities (see + /// [`Commands::spawn_empty`] and [`World::get_entity_mut`]). Lifetime `'a` corresponds to this + /// reborrowed self, and `Self` outlives it. + type SpawnOutput<'a>: BuildChildren + where + Self: 'a; + /// Spawns an entity with the given bundle and inserts it into the parent entity's [`Children`]. /// Also adds [`Parent`] component to the created entity. - pub fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands { + fn spawn(&mut self, bundle: impl Bundle) -> Self::SpawnOutput<'_>; + + /// Spawns an [`Entity`] with no components and inserts it into the parent entity's [`Children`]. + /// Also adds [`Parent`] component to the created entity. + fn spawn_empty(&mut self) -> Self::SpawnOutput<'_>; + + /// Returns the parent entity. + fn parent_entity(&self) -> Entity; + + /// Adds a command to be executed, like [`Commands::add`]. + fn add_command(&mut self, command: C) -> &mut Self; +} + +impl ChildBuild for ChildBuilder<'_> { + type SpawnOutput<'a> = EntityCommands<'a> where Self: 'a; + + fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands { let e = self.commands.spawn(bundle); self.push_children.children.push(e.id()); e } - /// Spawns an [`Entity`] with no components and inserts it into the parent entity's [`Children`]. - /// Also adds [`Parent`] component to the created entity. - pub fn spawn_empty(&mut self) -> EntityCommands { + fn spawn_empty(&mut self) -> EntityCommands { let e = self.commands.spawn_empty(); self.push_children.children.push(e.id()); e } - /// Returns the parent entity of this [`ChildBuilder`]. - pub fn parent_entity(&self) -> Entity { + fn parent_entity(&self) -> Entity { self.push_children.parent } - /// Adds a command to be executed, like [`Commands::add`]. - pub fn add_command(&mut self, command: C) -> &mut Self { + fn add_command(&mut self, command: C) -> &mut Self { self.commands.add(command); self } @@ -310,8 +335,12 @@ impl ChildBuilder<'_> { /// Trait for removing, adding and replacing children and parents of an entity. pub trait BuildChildren { - /// Takes a closure which builds children for this entity using [`ChildBuilder`]. - fn with_children(&mut self, f: impl FnOnce(&mut ChildBuilder)) -> &mut Self; + /// Child builder type. + type Builder<'a>: ChildBuild; + + /// Takes a closure which builds children for this entity using [`ChildBuild`]. + fn with_children(&mut self, f: impl FnOnce(&mut Self::Builder<'_>)) -> &mut Self; + /// Pushes children to the back of the builder's children. For any entities that are /// already a child of this one, this method does nothing. /// @@ -323,6 +352,7 @@ pub trait BuildChildren { /// /// Panics if any of the children are the same as the parent. fn push_children(&mut self, children: &[Entity]) -> &mut Self; + /// Inserts children at the given index. /// /// If the children were previously children of another parent, that parent's [`Children`] component @@ -333,10 +363,12 @@ pub trait BuildChildren { /// /// Panics if any of the children are the same as the parent. fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; + /// Removes the given children /// /// Removing all children from a parent causes its [`Children`] component to be removed from the entity. fn remove_children(&mut self, children: &[Entity]) -> &mut Self; + /// Adds a single child. /// /// If the children were previously children of another parent, that parent's [`Children`] component @@ -347,8 +379,10 @@ pub trait BuildChildren { /// /// Panics if the child is the same as the parent. fn add_child(&mut self, child: Entity) -> &mut Self; + /// Removes all children from this entity. The [`Children`] component will be removed if it exists, otherwise this does nothing. fn clear_children(&mut self) -> &mut Self; + /// Removes all current children from this entity, replacing them with the specified list of entities. /// /// The removed children will have their [`Parent`] component removed. @@ -357,6 +391,7 @@ pub trait BuildChildren { /// /// Panics if any of the children are the same as the parent. fn replace_children(&mut self, children: &[Entity]) -> &mut Self; + /// Sets the parent of this entity. /// /// If this entity already had a parent, the parent's [`Children`] component will have this @@ -367,6 +402,7 @@ pub trait BuildChildren { /// /// Panics if the parent is the same as the child. fn set_parent(&mut self, parent: Entity) -> &mut Self; + /// Removes the [`Parent`] of this entity. /// /// Also removes this entity from its parent's [`Children`] component. Removing all children from a parent causes @@ -375,7 +411,9 @@ pub trait BuildChildren { } impl BuildChildren for EntityCommands<'_> { - fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self { + type Builder<'a> = ChildBuilder<'a>; + + fn with_children(&mut self, spawn_children: impl FnOnce(&mut Self::Builder<'_>)) -> &mut Self { let parent = self.id(); let mut builder = ChildBuilder { commands: self.commands(), @@ -478,10 +516,10 @@ pub struct WorldChildBuilder<'w> { parent: Entity, } -impl<'w> WorldChildBuilder<'w> { - /// Spawns an entity with the given bundle and inserts it into the parent entity's [`Children`]. - /// Also adds [`Parent`] component to the created entity. - pub fn spawn(&mut self, bundle: impl Bundle) -> EntityWorldMut<'_> { +impl ChildBuild for WorldChildBuilder<'_> { + type SpawnOutput<'a> = EntityWorldMut<'a> where Self: 'a; + + fn spawn(&mut self, bundle: impl Bundle) -> EntityWorldMut { let entity = self.world.spawn((bundle, Parent(self.parent))).id(); push_child_unchecked(self.world, self.parent, entity); push_events( @@ -494,9 +532,7 @@ impl<'w> WorldChildBuilder<'w> { self.world.entity_mut(entity) } - /// Spawns an [`Entity`] with no components and inserts it into the parent entity's [`Children`]. - /// Also adds [`Parent`] component to the created entity. - pub fn spawn_empty(&mut self) -> EntityWorldMut<'_> { + fn spawn_empty(&mut self) -> EntityWorldMut { let entity = self.world.spawn(Parent(self.parent)).id(); push_child_unchecked(self.world, self.parent, entity); push_events( @@ -509,83 +545,19 @@ impl<'w> WorldChildBuilder<'w> { self.world.entity_mut(entity) } - /// Returns the parent entity of this [`WorldChildBuilder`]. - pub fn parent_entity(&self) -> Entity { + fn parent_entity(&self) -> Entity { self.parent } + + fn add_command(&mut self, command: C) -> &mut Self { + command.apply(self.world); + self + } } -/// Trait that defines adding, changing and children and parents of an entity directly through the [`World`]. -pub trait BuildWorldChildren { - /// Takes a closure which builds children for this entity using [`WorldChildBuilder`]. - fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self; +impl BuildChildren for EntityWorldMut<'_> { + type Builder<'a> = WorldChildBuilder<'a>; - /// Adds a single child. - /// - /// If the children were previously children of another parent, that parent's [`Children`] component - /// will have those children removed from its list. Removing all children from a parent causes its - /// [`Children`] component to be removed from the entity. - /// - /// # Panics - /// - /// Panics if the child is the same as the parent. - fn add_child(&mut self, child: Entity) -> &mut Self; - - /// Pushes children to the back of the builder's children. For any entities that are - /// already a child of this one, this method does nothing. - /// - /// If the children were previously children of another parent, that parent's [`Children`] component - /// will have those children removed from its list. Removing all children from a parent causes its - /// [`Children`] component to be removed from the entity. - /// - /// # Panics - /// - /// Panics if any of the children are the same as the parent. - fn push_children(&mut self, children: &[Entity]) -> &mut Self; - /// Inserts children at the given index. - /// - /// If the children were previously children of another parent, that parent's [`Children`] component - /// will have those children removed from its list. Removing all children from a parent causes its - /// [`Children`] component to be removed from the entity. - /// - /// # Panics - /// - /// Panics if any of the children are the same as the parent. - fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; - /// Removes the given children - /// - /// Removing all children from a parent causes its [`Children`] component to be removed from the entity. - fn remove_children(&mut self, children: &[Entity]) -> &mut Self; - - /// Sets the parent of this entity. - /// - /// If this entity already had a parent, the parent's [`Children`] component will have this - /// child removed from its list. Removing all children from a parent causes its [`Children`] - /// component to be removed from the entity. - /// - /// # Panics - /// - /// Panics if the parent is the same as the child. - fn set_parent(&mut self, parent: Entity) -> &mut Self; - - /// Removes the [`Parent`] of this entity. - /// - /// Also removes this entity from its parent's [`Children`] component. Removing all children from a parent causes - /// its [`Children`] component to be removed from the entity. - fn remove_parent(&mut self) -> &mut Self; - /// Removes all children from this entity. The [`Children`] component will be removed if it exists, otherwise this does nothing. - fn clear_children(&mut self) -> &mut Self; - /// Removes all current children from this entity, replacing them with the specified list of entities. - /// - /// The removed children will have their [`Parent`] component removed. - /// - /// # Panics - /// - /// Panics if any of the children are the same as the parent. - fn replace_children(&mut self, children: &[Entity]) -> &mut Self; -} - -impl<'w> BuildWorldChildren for EntityWorldMut<'w> { fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self { let parent = self.id(); self.world_scope(|world| { @@ -691,7 +663,7 @@ impl<'w> BuildWorldChildren for EntityWorldMut<'w> { #[cfg(test)] mod tests { - use super::{BuildChildren, BuildWorldChildren}; + use super::{BuildChildren, ChildBuild}; use crate::{ components::{Children, Parent}, HierarchyEvent::{self, ChildAdded, ChildMoved, ChildRemoved}, diff --git a/crates/bevy_hierarchy/src/hierarchy.rs b/crates/bevy_hierarchy/src/hierarchy.rs index 09a3fef010..d3db4dd4d8 100644 --- a/crates/bevy_hierarchy/src/hierarchy.rs +++ b/crates/bevy_hierarchy/src/hierarchy.rs @@ -146,7 +146,10 @@ mod tests { }; use super::DespawnRecursiveExt; - use crate::{child_builder::BuildChildren, components::Children}; + use crate::{ + child_builder::{BuildChildren, ChildBuild}, + components::Children, + }; #[derive(Component, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)] struct Idx(u32); diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs old mode 100644 new mode 100755 index 0be21f6d16..75fc849202 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -16,7 +16,7 @@ //! for managing parent-child relationships between entities. //! It provides two components, [`Parent`] and [`Children`], //! to store references to related entities. -//! It also provides [command] and [world] API extensions +//! It also provides [command and world] API extensions //! to set and clear those relationships. //! //! More advanced users may also appreciate @@ -44,13 +44,12 @@ //! In most cases, these operations will invalidate the hierarchy. //! Instead, you should use the provided [hierarchical despawn extension methods]. //! -//! [command]: BuildChildren +//! [command and world]: BuildChildren //! [diagnostic plugin]: ValidParentCheckPlugin //! [events]: HierarchyEvent //! [hierarchical despawn extension methods]: DespawnRecursiveExt //! [plugin]: HierarchyPlugin //! [query extension methods]: HierarchyQueryExt -//! [world]: BuildWorldChildren mod components; pub use components::*; diff --git a/crates/bevy_hierarchy/src/query_extension.rs b/crates/bevy_hierarchy/src/query_extension.rs index d78dee681c..3e6d02222a 100644 --- a/crates/bevy_hierarchy/src/query_extension.rs +++ b/crates/bevy_hierarchy/src/query_extension.rs @@ -161,7 +161,7 @@ mod tests { world::World, }; - use crate::{query_extension::HierarchyQueryExt, BuildWorldChildren, Children, Parent}; + use crate::{query_extension::HierarchyQueryExt, BuildChildren, Children, Parent}; #[derive(Component, PartialEq, Debug)] struct A(usize); diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index ea7749fa91..341404d189 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -501,7 +501,7 @@ mod test { use super::*; - use bevy_hierarchy::BuildWorldChildren; + use bevy_hierarchy::BuildChildren; fn visibility_bundle(visibility: Visibility) -> VisibilityBundle { VisibilityBundle { diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 8706937f34..e478e7b412 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ system::Resource, world::{Command, Mut, World}, }; -use bevy_hierarchy::{BuildWorldChildren, DespawnRecursiveExt, Parent, PushChild}; +use bevy_hierarchy::{BuildChildren, DespawnRecursiveExt, Parent, PushChild}; use bevy_utils::{tracing::error, HashMap, HashSet}; use thiserror::Error; use uuid::Uuid; diff --git a/crates/bevy_transform/src/helper.rs b/crates/bevy_transform/src/helper.rs index 0aa3195444..091e39e189 100644 --- a/crates/bevy_transform/src/helper.rs +++ b/crates/bevy_transform/src/helper.rs @@ -84,7 +84,7 @@ mod tests { use bevy_app::App; use bevy_ecs::system::SystemState; - use bevy_hierarchy::BuildWorldChildren; + use bevy_hierarchy::BuildChildren; use bevy_math::{Quat, Vec3}; use crate::{ diff --git a/crates/bevy_transform/src/systems.rs b/crates/bevy_transform/src/systems.rs index 442a49a32b..a9992d6d73 100644 --- a/crates/bevy_transform/src/systems.rs +++ b/crates/bevy_transform/src/systems.rs @@ -190,7 +190,7 @@ mod test { use crate::bundles::TransformBundle; use crate::systems::*; - use bevy_hierarchy::{BuildChildren, BuildWorldChildren}; + use bevy_hierarchy::{BuildChildren, ChildBuild}; #[test] fn correct_parent_removed() { diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index 154b85cb5e..0789feb45b 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -357,7 +357,9 @@ mod tests { use bevy_ecs::schedule::Schedule; use bevy_ecs::system::RunSystemOnce; use bevy_ecs::world::World; - use bevy_hierarchy::{despawn_with_children_recursive, BuildWorldChildren, Children, Parent}; + use bevy_hierarchy::{ + despawn_with_children_recursive, BuildChildren, ChildBuild, Children, Parent, + }; use bevy_math::{vec2, Rect, UVec2, Vec2}; use bevy_render::camera::ManualTextureViews; use bevy_render::camera::OrthographicProjection; diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index cea45e91bd..30b6c8e44a 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -158,7 +158,7 @@ mod tests { system::Commands, world::{CommandQueue, World}, }; - use bevy_hierarchy::BuildChildren; + use bevy_hierarchy::{BuildChildren, ChildBuild}; use crate::{Node, UiStack, ZIndex};