Skip to content

Commit b39817a

Browse files
committed
Add add_child, set_parent and remove_parent to EntityMut (#6926)
# Objective Align the hierarchy API between `EntityCommands` and `EntityMut`. Added missing methods to `EntityMut`. Replaced the duplicate `Command` implementations with the ones on `EntityMut` (e.g. The `AddChild` command is now just `world.entity_mut(..).add_child(..)`) Fixed `update_old_parents` not sending `ChildAdded` events. This PR does not add `add_children` to `EntityMut` as I would like to remove it from `EntityCommands` instead in #6942. ## Changelog * Added `add_child`, `set_parent` and `remove_parent` to `EntityMut` * Fixed missing `ChildAdded` events Co-authored-by: devil-ira <[email protected]>
1 parent 0d98327 commit b39817a

File tree

2 files changed

+237
-59
lines changed

2 files changed

+237
-59
lines changed

crates/bevy_hierarchy/src/child_builder.rs

Lines changed: 236 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ fn update_parent(world: &mut World, child: Entity, new_parent: Entity) -> Option
2828
}
2929
}
3030

31+
/// Remove child from the parent's [`Children`] component.
32+
///
33+
/// Removes the [`Children`] component from the parent if it's empty.
3134
fn remove_from_children(world: &mut World, parent: Entity, child: Entity) {
3235
let mut parent = world.entity_mut(parent);
3336
if let Some(mut children) = parent.get_mut::<Children>() {
@@ -38,24 +41,61 @@ fn remove_from_children(world: &mut World, parent: Entity, child: Entity) {
3841
}
3942
}
4043

44+
/// Update the [`Parent`] component of the `child`.
45+
/// Removes the `child` from the previous parent's [`Children`].
46+
///
47+
/// Does not update the new parents [`Children`] component.
48+
///
49+
/// Does nothing if `child` was already a child of `parent`.
50+
///
51+
/// Sends [`HierarchyEvent`]'s.
52+
fn update_old_parent(world: &mut World, child: Entity, parent: Entity) {
53+
let previous = update_parent(world, child, parent);
54+
if let Some(previous_parent) = previous {
55+
// Do nothing if the child was already parented to this entity.
56+
if previous_parent == parent {
57+
return;
58+
}
59+
remove_from_children(world, previous_parent, child);
60+
61+
world.send_event(HierarchyEvent::ChildMoved {
62+
child,
63+
previous_parent,
64+
new_parent: parent,
65+
});
66+
} else {
67+
world.send_event(HierarchyEvent::ChildAdded { child, parent });
68+
}
69+
}
70+
71+
/// Update the [`Parent`] components of the `children`.
72+
/// Removes the `children` from their previous parent's [`Children`].
73+
///
74+
/// Does not update the new parents [`Children`] component.
75+
///
76+
/// Does nothing for a child if it was already a child of `parent`.
77+
///
78+
/// Sends [`HierarchyEvent`]'s.
4179
fn update_old_parents(world: &mut World, parent: Entity, children: &[Entity]) {
42-
let mut moved: SmallVec<[HierarchyEvent; 8]> = SmallVec::with_capacity(children.len());
43-
for child in children {
44-
if let Some(previous) = update_parent(world, *child, parent) {
80+
let mut events: SmallVec<[HierarchyEvent; 8]> = SmallVec::with_capacity(children.len());
81+
for &child in children {
82+
if let Some(previous) = update_parent(world, child, parent) {
4583
// Do nothing if the entity already has the correct parent.
4684
if parent == previous {
4785
continue;
4886
}
4987

50-
remove_from_children(world, previous, *child);
51-
moved.push(HierarchyEvent::ChildMoved {
52-
child: *child,
88+
remove_from_children(world, previous, child);
89+
events.push(HierarchyEvent::ChildMoved {
90+
child,
5391
previous_parent: previous,
5492
new_parent: parent,
5593
});
94+
} else {
95+
events.push(HierarchyEvent::ChildAdded { child, parent });
5696
}
5797
}
58-
world.send_event_batch(moved);
98+
world.send_event_batch(events);
5999
}
60100

61101
fn remove_children(parent: Entity, children: &[Entity], world: &mut World) {
@@ -99,30 +139,7 @@ pub struct AddChild {
99139

100140
impl Command for AddChild {
101141
fn write(self, world: &mut World) {
102-
let previous = update_parent(world, self.child, self.parent);
103-
if let Some(previous) = previous {
104-
if previous == self.parent {
105-
return;
106-
}
107-
remove_from_children(world, previous, self.child);
108-
world.send_event(HierarchyEvent::ChildMoved {
109-
child: self.child,
110-
previous_parent: previous,
111-
new_parent: self.parent,
112-
});
113-
}
114-
world.send_event(HierarchyEvent::ChildAdded {
115-
child: self.child,
116-
parent: self.parent,
117-
});
118-
let mut parent = world.entity_mut(self.parent);
119-
if let Some(mut children) = parent.get_mut::<Children>() {
120-
if !children.contains(&self.child) {
121-
children.0.push(self.child);
122-
}
123-
} else {
124-
parent.insert(Children(smallvec::smallvec![self.child]));
125-
}
142+
world.entity_mut(self.parent).add_child(self.child);
126143
}
127144
}
128145

@@ -136,14 +153,9 @@ pub struct InsertChildren {
136153

137154
impl Command for InsertChildren {
138155
fn write(self, world: &mut World) {
139-
update_old_parents(world, self.parent, &self.children);
140-
let mut parent = world.entity_mut(self.parent);
141-
if let Some(mut children) = parent.get_mut::<Children>() {
142-
children.0.retain(|value| !self.children.contains(value));
143-
children.0.insert_from_slice(self.index, &self.children);
144-
} else {
145-
parent.insert(Children(self.children));
146-
}
156+
world
157+
.entity_mut(self.parent)
158+
.insert_children(self.index, &self.children);
147159
}
148160
}
149161

@@ -155,15 +167,8 @@ pub struct PushChildren {
155167
}
156168

157169
impl Command for PushChildren {
158-
fn write(mut self, world: &mut World) {
159-
update_old_parents(world, self.parent, &self.children);
160-
let mut parent = world.entity_mut(self.parent);
161-
if let Some(mut children) = parent.get_mut::<Children>() {
162-
children.0.retain(|child| !self.children.contains(child));
163-
children.0.append(&mut self.children);
164-
} else {
165-
parent.insert(Children(self.children));
166-
}
170+
fn write(self, world: &mut World) {
171+
world.entity_mut(self.parent).push_children(&self.children);
167172
}
168173
}
169174

@@ -186,15 +191,7 @@ pub struct RemoveParent {
186191

187192
impl Command for RemoveParent {
188193
fn write(self, world: &mut World) {
189-
if let Some(parent) = world.get::<Parent>(self.child) {
190-
let parent_entity = parent.get();
191-
remove_from_children(world, parent_entity, self.child);
192-
world.entity_mut(self.child).remove::<Parent>();
193-
world.send_event(HierarchyEvent::ChildRemoved {
194-
child: self.child,
195-
parent: parent_entity,
196-
});
197-
}
194+
world.entity_mut(self.child).remove_parent();
198195
}
199196
}
200197

@@ -368,12 +365,28 @@ impl<'w> WorldChildBuilder<'w> {
368365
pub trait BuildWorldChildren {
369366
/// Creates a [`WorldChildBuilder`] with the given children built in the given closure
370367
fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self;
368+
369+
/// Adds a single child
370+
///
371+
/// If the children were previously children of another parent, that parent's [`Children`] component
372+
/// will have those children removed from its list. Removing all children from a parent causes its
373+
/// [`Children`] component to be removed from the entity.
374+
fn add_child(&mut self, child: Entity) -> &mut Self;
375+
371376
/// Pushes children to the back of the builder's children
372377
fn push_children(&mut self, children: &[Entity]) -> &mut Self;
373378
/// Inserts children at the given index
374379
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self;
375380
/// Removes the given children
376381
fn remove_children(&mut self, children: &[Entity]) -> &mut Self;
382+
383+
/// Set the `parent` of this entity. This entity will be added to the end of the `parent`'s list of children.
384+
///
385+
/// If this entity already had a parent it will be removed from it.
386+
fn set_parent(&mut self, parent: Entity) -> &mut Self;
387+
388+
/// Remove the parent from this entity.
389+
fn remove_parent(&mut self) -> &mut Self;
377390
}
378391

379392
impl<'w> BuildWorldChildren for EntityMut<'w> {
@@ -385,6 +398,20 @@ impl<'w> BuildWorldChildren for EntityMut<'w> {
385398
self
386399
}
387400

401+
fn add_child(&mut self, child: Entity) -> &mut Self {
402+
let parent = self.id();
403+
self.world_scope(|world| {
404+
update_old_parent(world, child, parent);
405+
});
406+
if let Some(mut children_component) = self.get_mut::<Children>() {
407+
children_component.0.retain(|value| child != *value);
408+
children_component.0.push(child);
409+
} else {
410+
self.insert(Children::from_entities(&[child]));
411+
}
412+
self
413+
}
414+
388415
fn push_children(&mut self, children: &[Entity]) -> &mut Self {
389416
let parent = self.id();
390417
self.world_scope(|world| {
@@ -424,21 +451,172 @@ impl<'w> BuildWorldChildren for EntityMut<'w> {
424451
});
425452
self
426453
}
454+
455+
fn set_parent(&mut self, parent: Entity) -> &mut Self {
456+
let child = self.id();
457+
self.world_scope(|world| {
458+
world.entity_mut(parent).add_child(child);
459+
});
460+
self
461+
}
462+
463+
fn remove_parent(&mut self) -> &mut Self {
464+
let child = self.id();
465+
if let Some(parent) = self.remove::<Parent>().map(|p| p.get()) {
466+
self.world_scope(|world| {
467+
remove_from_children(world, parent, child);
468+
world.send_event(HierarchyEvent::ChildRemoved { child, parent });
469+
});
470+
}
471+
self
472+
}
427473
}
428474

429475
#[cfg(test)]
430476
mod tests {
431477
use super::{BuildChildren, BuildWorldChildren};
432-
use crate::prelude::{Children, Parent};
478+
use crate::{
479+
components::{Children, Parent},
480+
HierarchyEvent::{self, ChildAdded, ChildMoved, ChildRemoved},
481+
};
433482
use smallvec::{smallvec, SmallVec};
434483

435484
use bevy_ecs::{
436485
component::Component,
437486
entity::Entity,
487+
event::Events,
438488
system::{CommandQueue, Commands},
439489
world::World,
440490
};
441491

492+
/// Assert the (non)existence and state of the child's [`Parent`] component.
493+
fn assert_parent(world: &mut World, child: Entity, parent: Option<Entity>) {
494+
assert_eq!(world.get::<Parent>(child).map(|p| p.get()), parent);
495+
}
496+
497+
/// Assert the (non)existence and state of the parent's [`Children`] component.
498+
fn assert_children(world: &mut World, parent: Entity, children: Option<&[Entity]>) {
499+
assert_eq!(world.get::<Children>(parent).map(|c| &**c), children);
500+
}
501+
502+
/// Used to omit a number of events that are not relevant to a particular test.
503+
fn omit_events(world: &mut World, number: usize) {
504+
let mut events_resource = world.resource_mut::<Events<HierarchyEvent>>();
505+
let mut events: Vec<_> = events_resource.drain().collect();
506+
events_resource.extend(events.drain(number..));
507+
}
508+
509+
fn assert_events(world: &mut World, expected_events: &[HierarchyEvent]) {
510+
let events: Vec<_> = world
511+
.resource_mut::<Events<HierarchyEvent>>()
512+
.drain()
513+
.collect();
514+
assert_eq!(events, expected_events);
515+
}
516+
517+
#[test]
518+
fn add_child() {
519+
let world = &mut World::new();
520+
world.insert_resource(Events::<HierarchyEvent>::default());
521+
522+
let [a, b, c, d] = std::array::from_fn(|_| world.spawn_empty().id());
523+
524+
world.entity_mut(a).add_child(b);
525+
526+
assert_parent(world, b, Some(a));
527+
assert_children(world, a, Some(&[b]));
528+
assert_events(
529+
world,
530+
&[ChildAdded {
531+
child: b,
532+
parent: a,
533+
}],
534+
);
535+
536+
world.entity_mut(a).add_child(c);
537+
538+
assert_children(world, a, Some(&[b, c]));
539+
assert_parent(world, c, Some(a));
540+
assert_events(
541+
world,
542+
&[ChildAdded {
543+
child: c,
544+
parent: a,
545+
}],
546+
);
547+
// Children component should be removed when it's empty.
548+
world.entity_mut(d).add_child(b).add_child(c);
549+
assert_children(world, a, None);
550+
}
551+
552+
#[test]
553+
fn set_parent() {
554+
let world = &mut World::new();
555+
world.insert_resource(Events::<HierarchyEvent>::default());
556+
557+
let [a, b, c] = std::array::from_fn(|_| world.spawn_empty().id());
558+
559+
world.entity_mut(a).set_parent(b);
560+
561+
assert_parent(world, a, Some(b));
562+
assert_children(world, b, Some(&[a]));
563+
assert_events(
564+
world,
565+
&[ChildAdded {
566+
child: a,
567+
parent: b,
568+
}],
569+
);
570+
571+
world.entity_mut(a).set_parent(c);
572+
573+
assert_parent(world, a, Some(c));
574+
assert_children(world, b, None);
575+
assert_children(world, c, Some(&[a]));
576+
assert_events(
577+
world,
578+
&[ChildMoved {
579+
child: a,
580+
previous_parent: b,
581+
new_parent: c,
582+
}],
583+
);
584+
}
585+
586+
#[test]
587+
fn remove_parent() {
588+
let world = &mut World::new();
589+
world.insert_resource(Events::<HierarchyEvent>::default());
590+
591+
let [a, b, c] = std::array::from_fn(|_| world.spawn_empty().id());
592+
593+
world.entity_mut(a).push_children(&[b, c]);
594+
world.entity_mut(b).remove_parent();
595+
596+
assert_parent(world, b, None);
597+
assert_parent(world, c, Some(a));
598+
assert_children(world, a, Some(&[c]));
599+
omit_events(world, 2); // Omit ChildAdded events.
600+
assert_events(
601+
world,
602+
&[ChildRemoved {
603+
child: b,
604+
parent: a,
605+
}],
606+
);
607+
608+
world.entity_mut(c).remove_parent();
609+
assert_parent(world, c, None);
610+
assert_children(world, a, None);
611+
assert_events(
612+
world,
613+
&[ChildRemoved {
614+
child: c,
615+
parent: a,
616+
}],
617+
);
618+
}
619+
442620
#[derive(Component)]
443621
struct C(u32);
444622

crates/bevy_hierarchy/src/events.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bevy_ecs::prelude::Entity;
33
/// An [`Event`] that is fired whenever there is a change in the world's hierarchy.
44
///
55
/// [`Event`]: bevy_ecs::event::Event
6-
#[derive(Debug, Clone)]
6+
#[derive(Debug, Clone, PartialEq, Eq)]
77
pub enum HierarchyEvent {
88
/// Fired whenever an [`Entity`] is added as a child to a parent.
99
ChildAdded {

0 commit comments

Comments
 (0)