Merge BuildWorldChildren and BuildChildren traits. (#14052)

# Objective

The `BuildChildren` and `BuildWorldChildren` traits are mostly
identical, so I decided to try and merge them. I'm not sure of the
history, maybe they were added before GATs existed.

## Solution

- Add an associated type to `BuildChildren` which reflects the prior
differences between the `BuildChildren` and `BuildWorldChildren` traits.
- Add `ChildBuild` trait that is the bounds for
`BuildChildren::Builder`, with impls for `ChildBuilder` and
`WorldChildBuilder`.
- Remove `BuildWorldChildren` trait and replace it with an impl of
`BuildChildren` for `EntityWorldMut`.

## Testing

I ran several of the examples that use entity hierarchies, mainly UI.

---

## Changelog

n/a

## Migration Guide

n/a
This commit is contained in:
Al M 2024-07-01 07:29:39 -07:00 committed by GitHub
parent 6dcff2bfe8
commit ace4eaaf0e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 82 additions and 106 deletions

View file

@ -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},

View file

@ -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,

View file

@ -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<C: 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<C: Command>(&mut self, command: C) -> &mut Self {
fn add_command<C: 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<C: 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},

View file

@ -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);

5
crates/bevy_hierarchy/src/lib.rs Normal file → Executable file
View file

@ -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::*;

View file

@ -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);

View file

@ -501,7 +501,7 @@ mod test {
use super::*;
use bevy_hierarchy::BuildWorldChildren;
use bevy_hierarchy::BuildChildren;
fn visibility_bundle(visibility: Visibility) -> VisibilityBundle {
VisibilityBundle {

View file

@ -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;

View file

@ -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::{

View file

@ -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() {

View file

@ -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;

View file

@ -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};