Refactor hierarchy-related commands to remove structs (#17029)

## Objective

Continuation of #16999.

This PR handles the following:
- Many hierarchy-related commands are wrappers around `World` and
`EntityWorldMut` methods and can be moved to closures:
  - `AddChild`
  - `InsertChildren`
  - `AddChildren`
  - `RemoveChildren`
  - `ClearChildren`
  - `ReplaceChildren`
  - `RemoveParent`
  - `DespawnRecursive`
  - `DespawnChildrenRecursive`
  - `AddChildInPlace`
  - `RemoveParentInPlace`
- `SendEvent` is a wrapper around `World` methods and can be moved to a
closure (and its file deleted).

## Migration Guide

If you were queuing the structs of hierarchy-related commands or
`SendEvent` directly, you will need to change them to the methods
implemented on `EntityCommands` (or `Commands` for `SendEvent`):

| Struct | Method |

|--------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
| `commands.queue(AddChild { child, parent });` |
`commands.entity(parent).add_child(child);` OR
`commands.entity(child).set_parent(parent);` |
| `commands.queue(AddChildren { children, parent });` |
`commands.entity(parent).add_children(children);` |
| `commands.queue(InsertChildren { children, parent });` |
`commands.entity(parent).insert_children(children);` |
| `commands.queue(RemoveChildren { children, parent });` |
`commands.entity(parent).remove_children(children);` |
| `commands.queue(ReplaceChildren { children, parent });` |
`commands.entity(parent).replace_children(children);` |
| `commands.queue(ClearChildren { parent });` |
`commands.entity(parent).clear_children();` |
| `commands.queue(RemoveParent { child });` |
`commands.entity(child).remove_parent()` |
| `commands.queue(DespawnRecursive { entity, warn: true });` |
`commands.entity(entity).despawn_recursive();` |
| `commands.queue(DespawnRecursive { entity, warn: false });` |
`commands.entity(entity).try_despawn_recursive();` |
| `commands.queue(DespawnChildrenRecursive { entity, warn: true });` |
`commands.entity(entity).despawn_descendants();` |
| `commands.queue(DespawnChildrenRecursive { entity, warn: false});` |
`commands.entity(entity).try_despawn_descendants();` |
| `commands.queue(SendEvent { event });` | `commands.send_event(event);`
|
This commit is contained in:
JaySpruce 2024-12-30 14:58:03 -06:00 committed by GitHub
parent 4f9dc6534b
commit 9ac7e17f2e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 163 additions and 368 deletions

View File

@ -7,7 +7,6 @@ mod mut_iterators;
mod mutator;
mod reader;
mod registry;
mod send_event;
mod update;
mod writer;
@ -25,7 +24,6 @@ pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId};
pub use mutator::EventMutator;
pub use reader::EventReader;
pub use registry::{EventRegistry, ShouldUpdateEvents};
pub use send_event::SendEvent;
pub use update::{
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
};

View File

@ -1,37 +0,0 @@
#[cfg(feature = "track_change_detection")]
use core::panic::Location;
use super::{Event, Events};
use crate::world::{Command, World};
/// A command to send an arbitrary [`Event`], used by [`Commands::send_event`](crate::system::Commands::send_event).
pub struct SendEvent<E: Event> {
/// The event to send.
pub event: E,
/// The source code location that triggered this command.
#[cfg(feature = "track_change_detection")]
pub caller: &'static Location<'static>,
}
// This does not use `From`, as the resulting `Into` is not track_caller
impl<E: Event> SendEvent<E> {
/// Constructs a new `SendEvent` tracking the caller.
pub fn new(event: E) -> Self {
Self {
event,
#[cfg(feature = "track_change_detection")]
caller: Location::caller(),
}
}
}
impl<E: Event> Command for SendEvent<E> {
fn apply(self, world: &mut World) {
let mut events = world.resource_mut::<Events<E>>();
events.send_with_caller(
self.event,
#[cfg(feature = "track_change_detection")]
self.caller,
);
}
}

View File

@ -11,7 +11,7 @@ use crate::{
change_detection::Mut,
component::{Component, ComponentId, ComponentInfo, Mutable},
entity::{Entities, Entity, EntityCloneBuilder},
event::{Event, SendEvent},
event::{Event, Events},
observer::{Observer, TriggerTargets},
schedule::ScheduleLabel,
system::{input::SystemInput, SystemId},
@ -1060,10 +1060,15 @@ impl<'w, 's> Commands<'w, 's> {
/// [`EventWriter`]: crate::event::EventWriter
#[track_caller]
pub fn send_event<E: Event>(&mut self, event: E) -> &mut Self {
self.queue(SendEvent {
event,
#[cfg(feature = "track_change_detection")]
caller: Location::caller(),
#[cfg(feature = "track_change_detection")]
let caller = Location::caller();
self.queue(move |world: &mut World| {
let mut events = world.resource_mut::<Events<E>>();
events.send_with_caller(
event,
#[cfg(feature = "track_change_detection")]
caller,
);
});
self
}

View File

@ -2,7 +2,7 @@ use crate::{Children, HierarchyEvent, Parent};
use bevy_ecs::{
bundle::Bundle,
entity::Entity,
prelude::Events,
event::Events,
system::{Commands, EntityCommands},
world::{Command, EntityWorldMut, World},
};
@ -149,109 +149,6 @@ fn remove_children(parent: Entity, children: &[Entity], world: &mut World) {
}
}
/// Removes all children from `parent` by removing its [`Children`] component, as well as removing
/// [`Parent`] component from its children.
fn clear_children(parent: Entity, world: &mut World) {
if let Some(children) = world.entity_mut(parent).take::<Children>() {
for &child in &children.0 {
world.entity_mut(child).remove::<Parent>();
}
}
}
/// Command that adds a child to an entity.
#[derive(Debug)]
pub struct AddChild {
/// Parent entity to add the child to.
pub parent: Entity,
/// Child entity to add.
pub child: Entity,
}
impl Command for AddChild {
fn apply(self, world: &mut World) {
world.entity_mut(self.parent).add_child(self.child);
}
}
/// Command that inserts a child at a given index of a parent's children, shifting following children back.
#[derive(Debug)]
pub struct InsertChildren {
parent: Entity,
children: SmallVec<[Entity; 8]>,
index: usize,
}
impl Command for InsertChildren {
fn apply(self, world: &mut World) {
world
.entity_mut(self.parent)
.insert_children(self.index, &self.children);
}
}
/// Command that pushes children to the end of the entity's [`Children`].
#[derive(Debug)]
pub struct AddChildren {
parent: Entity,
children: SmallVec<[Entity; 8]>,
}
impl Command for AddChildren {
fn apply(self, world: &mut World) {
world.entity_mut(self.parent).add_children(&self.children);
}
}
/// Command that removes children from an entity, and removes these children's parent.
pub struct RemoveChildren {
parent: Entity,
children: SmallVec<[Entity; 8]>,
}
impl Command for RemoveChildren {
fn apply(self, world: &mut World) {
remove_children(self.parent, &self.children, world);
}
}
/// Command that clears all children from an entity and removes [`Parent`] component from those
/// children.
pub struct ClearChildren {
parent: Entity,
}
impl Command for ClearChildren {
fn apply(self, world: &mut World) {
clear_children(self.parent, world);
}
}
/// Command that clear all children from an entity, replacing them with the given children.
pub struct ReplaceChildren {
parent: Entity,
children: SmallVec<[Entity; 8]>,
}
impl Command for ReplaceChildren {
fn apply(self, world: &mut World) {
clear_children(self.parent, world);
world.entity_mut(self.parent).add_children(&self.children);
}
}
/// Command that removes the parent of an entity, and removes that entity from the parent's [`Children`].
pub struct RemoveParent {
/// `Entity` whose parent must be removed.
pub child: Entity,
}
impl Command for RemoveParent {
fn apply(self, world: &mut World) {
world.entity_mut(self.child).remove_parent();
}
}
/// Struct for building children entities and adding them to a parent entity.
///
/// # Example
@ -276,7 +173,8 @@ impl Command for RemoveParent {
/// ```
pub struct ChildBuilder<'a> {
commands: Commands<'a, 'a>,
add_children: AddChildren,
children: SmallVec<[Entity; 8]>,
parent: Entity,
}
/// Trait for building children entities and adding them to a parent entity. This is used in
@ -316,18 +214,18 @@ impl ChildBuild for ChildBuilder<'_> {
fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands {
let e = self.commands.spawn(bundle);
self.add_children.children.push(e.id());
self.children.push(e.id());
e
}
fn spawn_empty(&mut self) -> EntityCommands {
let e = self.commands.spawn_empty();
self.add_children.children.push(e.id());
self.children.push(e.id());
e
}
fn parent_entity(&self) -> Entity {
self.add_children.parent
self.parent
}
fn queue_command<C: Command>(&mut self, command: C) -> &mut Self {
@ -431,38 +329,37 @@ impl BuildChildren for EntityCommands<'_> {
let parent = self.id();
let mut builder = ChildBuilder {
commands: self.commands(),
add_children: AddChildren {
children: SmallVec::default(),
parent,
},
children: SmallVec::default(),
parent,
};
spawn_children(&mut builder);
let children = builder.add_children;
if children.children.contains(&parent) {
let children = builder.children;
if children.contains(&parent) {
panic!("Entity cannot be a child of itself.");
}
self.commands().queue(children);
self
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).add_children(&children);
})
}
fn with_child<B: Bundle>(&mut self, bundle: B) -> &mut Self {
let parent = self.id();
let child = self.commands().spawn(bundle).id();
self.commands().queue(AddChild { parent, child });
self
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).add_child(child);
})
}
fn add_children(&mut self, children: &[Entity]) -> &mut Self {
let parent = self.id();
if children.contains(&parent) {
panic!("Cannot push entity as a child of itself.");
panic!("Cannot add entity as a child of itself.");
}
self.commands().queue(AddChildren {
children: SmallVec::from(children),
parent,
});
self
let children = SmallVec::<[Entity; 8]>::from_slice(children);
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).add_children(&children);
})
}
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self {
@ -470,21 +367,17 @@ impl BuildChildren for EntityCommands<'_> {
if children.contains(&parent) {
panic!("Cannot insert entity as a child of itself.");
}
self.commands().queue(InsertChildren {
children: SmallVec::from(children),
index,
parent,
});
self
let children = SmallVec::<[Entity; 8]>::from_slice(children);
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).insert_children(index, &children);
})
}
fn remove_children(&mut self, children: &[Entity]) -> &mut Self {
let parent = self.id();
self.commands().queue(RemoveChildren {
children: SmallVec::from(children),
parent,
});
self
let children = SmallVec::<[Entity; 8]>::from_slice(children);
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).remove_children(&children);
})
}
fn add_child(&mut self, child: Entity) -> &mut Self {
@ -492,14 +385,15 @@ impl BuildChildren for EntityCommands<'_> {
if child == parent {
panic!("Cannot add entity as a child of itself.");
}
self.commands().queue(AddChild { child, parent });
self
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).add_child(child);
})
}
fn clear_children(&mut self) -> &mut Self {
let parent = self.id();
self.commands().queue(ClearChildren { parent });
self
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).clear_children();
})
}
fn replace_children(&mut self, children: &[Entity]) -> &mut Self {
@ -507,11 +401,10 @@ impl BuildChildren for EntityCommands<'_> {
if children.contains(&parent) {
panic!("Cannot replace entity as a child of itself.");
}
self.commands().queue(ReplaceChildren {
children: SmallVec::from(children),
parent,
});
self
let children = SmallVec::<[Entity; 8]>::from_slice(children);
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).replace_children(&children);
})
}
fn set_parent(&mut self, parent: Entity) -> &mut Self {
@ -519,14 +412,15 @@ impl BuildChildren for EntityCommands<'_> {
if child == parent {
panic!("Cannot set parent to itself");
}
self.commands().queue(AddChild { child, parent });
self
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(parent).add_child(entity);
})
}
fn remove_parent(&mut self) -> &mut Self {
let child = self.id();
self.commands().queue(RemoveParent { child });
self
self.queue(move |entity: Entity, world: &mut World| {
world.entity_mut(entity).remove_parent();
})
}
}
@ -557,16 +451,7 @@ impl ChildBuild for WorldChildBuilder<'_> {
}
fn spawn_empty(&mut self) -> EntityWorldMut {
let entity = self.world.spawn(Parent(self.parent)).id();
add_child_unchecked(self.world, self.parent, entity);
push_events(
self.world,
[HierarchyEvent::ChildAdded {
child: entity,
parent: self.parent,
}],
);
self.world.entity_mut(entity)
self.spawn(())
}
fn parent_entity(&self) -> Entity {
@ -691,7 +576,11 @@ impl BuildChildren for EntityWorldMut<'_> {
fn clear_children(&mut self) -> &mut Self {
let parent = self.id();
self.world_scope(|world| {
clear_children(parent, world);
if let Some(children) = world.entity_mut(parent).take::<Children>() {
for &child in &children.0 {
world.entity_mut(child).remove::<Parent>();
}
}
});
self
}

View File

@ -6,28 +6,10 @@ use bevy_ecs::{
component::ComponentCloneHandler,
entity::{ComponentCloneCtx, Entity, EntityCloneBuilder},
system::EntityCommands,
world::{Command, DeferredWorld, EntityWorldMut, World},
world::{DeferredWorld, EntityWorldMut, World},
};
use log::debug;
/// Despawns the given entity and all its children recursively
#[derive(Debug)]
pub struct DespawnRecursive {
/// Target entity
pub entity: Entity,
/// Whether or not this command should output a warning if the entity does not exist
pub warn: bool,
}
/// Despawns the given entity's children recursively
#[derive(Debug)]
pub struct DespawnChildrenRecursive {
/// Target entity
pub entity: Entity,
/// Whether or not this command should output a warning if the entity does not exist
pub warn: bool,
}
/// Function for despawning an entity and all its children
pub fn despawn_with_children_recursive(world: &mut World, entity: Entity, warn: bool) {
// first, make the entity's own parent forget about it
@ -41,7 +23,7 @@ pub fn despawn_with_children_recursive(world: &mut World, entity: Entity, warn:
despawn_with_children_recursive_inner(world, entity, warn);
}
// Should only be called by `despawn_with_children_recursive` and `try_despawn_with_children_recursive`!
// Should only be called by `despawn_with_children_recursive` and `despawn_children_recursive`!
fn despawn_with_children_recursive_inner(world: &mut World, entity: Entity, warn: bool) {
if let Some(mut children) = world.get_mut::<Children>(entity) {
for e in core::mem::take(&mut children.0) {
@ -66,35 +48,6 @@ fn despawn_children_recursive(world: &mut World, entity: Entity, warn: bool) {
}
}
impl Command for DespawnRecursive {
fn apply(self, world: &mut World) {
#[cfg(feature = "trace")]
let _span = tracing::info_span!(
"command",
name = "DespawnRecursive",
entity = tracing::field::debug(self.entity),
warn = tracing::field::debug(self.warn)
)
.entered();
despawn_with_children_recursive(world, self.entity, self.warn);
}
}
impl Command for DespawnChildrenRecursive {
fn apply(self, world: &mut World) {
#[cfg(feature = "trace")]
let _span = tracing::info_span!(
"command",
name = "DespawnChildrenRecursive",
entity = tracing::field::debug(self.entity),
warn = tracing::field::debug(self.warn)
)
.entered();
despawn_children_recursive(world, self.entity, self.warn);
}
}
/// Trait that holds functions for despawning recursively down the transform hierarchy
pub trait DespawnRecursiveExt {
/// Despawns the provided entity alongside all descendants.
@ -114,33 +67,65 @@ impl DespawnRecursiveExt for EntityCommands<'_> {
/// Despawns the provided entity and its children.
/// This will emit warnings for any entity that does not exist.
fn despawn_recursive(mut self) {
let entity = self.id();
self.commands()
.queue(DespawnRecursive { entity, warn: true });
let warn = true;
self.queue(move |entity: Entity, world: &mut World| {
#[cfg(feature = "trace")]
let _span = tracing::info_span!(
"command",
name = "DespawnRecursive",
entity = tracing::field::debug(entity),
warn = tracing::field::debug(warn)
)
.entered();
despawn_with_children_recursive(world, entity, warn);
});
}
fn despawn_descendants(&mut self) -> &mut Self {
let entity = self.id();
self.commands()
.queue(DespawnChildrenRecursive { entity, warn: true });
let warn = true;
self.queue(move |entity: Entity, world: &mut World| {
#[cfg(feature = "trace")]
let _span = tracing::info_span!(
"command",
name = "DespawnChildrenRecursive",
entity = tracing::field::debug(entity),
warn = tracing::field::debug(warn)
)
.entered();
despawn_children_recursive(world, entity, warn);
});
self
}
/// Despawns the provided entity and its children.
/// This will never emit warnings.
fn try_despawn_recursive(mut self) {
let entity = self.id();
self.commands().queue(DespawnRecursive {
entity,
warn: false,
let warn = false;
self.queue(move |entity: Entity, world: &mut World| {
#[cfg(feature = "trace")]
let _span = tracing::info_span!(
"command",
name = "TryDespawnRecursive",
entity = tracing::field::debug(entity),
warn = tracing::field::debug(warn)
)
.entered();
despawn_with_children_recursive(world, entity, warn);
});
}
fn try_despawn_descendants(&mut self) -> &mut Self {
let entity = self.id();
self.commands().queue(DespawnChildrenRecursive {
entity,
warn: false,
let warn = false;
self.queue(move |entity: Entity, world: &mut World| {
#[cfg(feature = "trace")]
let _span = tracing::info_span!(
"command",
name = "TryDespawnChildrenRecursive",
entity = tracing::field::debug(entity),
warn = tracing::field::debug(warn)
)
.entered();
despawn_children_recursive(world, entity, warn);
});
self
}

View File

@ -204,9 +204,9 @@ mod tests {
},
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
system::Resource,
world::{Command, World},
world::World,
};
use bevy_hierarchy::{AddChild, Parent};
use bevy_hierarchy::{BuildChildren, Parent};
use bevy_reflect::Reflect;
use crate::dynamic_scene::DynamicScene;
@ -271,11 +271,9 @@ mod tests {
.register::<Parent>();
let original_parent_entity = world.spawn_empty().id();
let original_child_entity = world.spawn_empty().id();
AddChild {
parent: original_parent_entity,
child: original_child_entity,
}
.apply(&mut world);
world
.entity_mut(original_parent_entity)
.add_child(original_child_entity);
// We then write this relationship to a new scene, and then write that scene back to the
// world to create another parent and child relationship
@ -292,11 +290,9 @@ mod tests {
// We then add the parent from the scene as a child of the original child
// Hierarchy should look like:
// Original Parent <- Original Child <- Scene Parent <- Scene Child
AddChild {
parent: original_child_entity,
child: from_scene_parent_entity,
}
.apply(&mut world);
world
.entity_mut(original_child_entity)
.add_child(from_scene_parent_entity);
// We then reload the scene to make sure that from_scene_parent_entity's parent component
// isn't updated with the entity map, since this component isn't defined in the scene.

View File

@ -5,9 +5,9 @@ use bevy_ecs::{
event::{Event, EventCursor, Events},
reflect::AppTypeRegistry,
system::Resource,
world::{Command, Mut, World},
world::{Mut, World},
};
use bevy_hierarchy::{AddChild, BuildChildren, DespawnRecursiveExt, Parent};
use bevy_hierarchy::{BuildChildren, DespawnRecursiveExt, Parent};
use bevy_reflect::Reflect;
use bevy_utils::{HashMap, HashSet};
use thiserror::Error;
@ -382,11 +382,7 @@ impl SceneSpawner {
// this case shouldn't happen anyway
.unwrap_or(true)
{
AddChild {
parent,
child: entity,
}
.apply(world);
world.entity_mut(parent).add_child(entity);
}
}

View File

@ -3,83 +3,19 @@
use crate::prelude::{GlobalTransform, Transform};
use bevy_ecs::{
prelude::Entity,
entity::Entity,
system::EntityCommands,
world::{Command, EntityWorldMut, World},
world::{EntityWorldMut, World},
};
use bevy_hierarchy::{AddChild, RemoveParent};
use bevy_hierarchy::BuildChildren;
/// Command similar to [`AddChild`], but updating the child transform to keep
/// it at the same [`GlobalTransform`].
///
/// You most likely want to use [`BuildChildrenTransformExt::set_parent_in_place`]
/// method on [`EntityCommands`] instead.
pub struct AddChildInPlace {
/// Parent entity to add the child to.
pub parent: Entity,
/// Child entity to add.
pub child: Entity,
}
impl Command for AddChildInPlace {
fn apply(self, world: &mut World) {
let hierarchy_command = AddChild {
child: self.child,
parent: self.parent,
};
hierarchy_command.apply(world);
// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.
let mut update_transform = || {
let parent = *world
.get_entity(self.parent)
.ok()?
.get::<GlobalTransform>()?;
let child_global = *world
.get_entity(self.child)
.ok()?
.get::<GlobalTransform>()?;
let mut child_entity = world.get_entity_mut(self.child).ok()?;
let mut child = child_entity.get_mut::<Transform>()?;
*child = child_global.reparented_to(&parent);
Some(())
};
update_transform();
}
}
/// Command similar to [`RemoveParent`], but updating the child transform to keep
/// it at the same [`GlobalTransform`].
///
/// You most likely want to use [`BuildChildrenTransformExt::remove_parent_in_place`]
/// method on [`EntityCommands`] instead.
pub struct RemoveParentInPlace {
/// [`Entity`] whose parent must be removed.
pub child: Entity,
}
impl Command for RemoveParentInPlace {
fn apply(self, world: &mut World) {
let hierarchy_command = RemoveParent { child: self.child };
hierarchy_command.apply(world);
// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.
let mut update_transform = || {
let child_global = *world
.get_entity(self.child)
.ok()?
.get::<GlobalTransform>()?;
let mut child_entity = world.get_entity_mut(self.child).ok()?;
let mut child = child_entity.get_mut::<Transform>()?;
*child = child_global.compute_transform();
Some(())
};
update_transform();
}
}
/// Collection of methods similar to [`BuildChildren`](bevy_hierarchy::BuildChildren), but preserving each
/// Collection of methods similar to [`BuildChildren`], but preserving each
/// entity's [`GlobalTransform`].
pub trait BuildChildrenTransformExt {
/// Change this entity's parent while preserving this entity's [`GlobalTransform`]
/// by updating its [`Transform`].
///
/// See [`BuildChildren::set_parent`](bevy_hierarchy::BuildChildren::set_parent) for a method that doesn't update the
/// [`Transform`].
/// See [`BuildChildren::set_parent`] for a method that doesn't update the [`Transform`].
///
/// Note that both the hierarchy and transform updates will only execute
/// the next time commands are applied
@ -89,38 +25,65 @@ pub trait BuildChildrenTransformExt {
/// Make this entity parentless while preserving this entity's [`GlobalTransform`]
/// by updating its [`Transform`] to be equal to its current [`GlobalTransform`].
///
/// See [`BuildChildren::remove_parent`](bevy_hierarchy::BuildChildren::remove_parent) for a method that doesn't update the
/// [`Transform`].
/// See [`BuildChildren::remove_parent`] for a method that doesn't update the [`Transform`].
///
/// Note that both the hierarchy and transform updates will only execute
/// the next time commands are applied
/// (during [`ApplyDeferred`](bevy_ecs::schedule::ApplyDeferred)).
fn remove_parent_in_place(&mut self) -> &mut Self;
}
impl BuildChildrenTransformExt for EntityCommands<'_> {
fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {
let child = self.id();
self.commands().queue(AddChildInPlace { child, parent });
self
self.queue(move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.set_parent_in_place(parent);
}
})
}
fn remove_parent_in_place(&mut self) -> &mut Self {
let child = self.id();
self.commands().queue(RemoveParentInPlace { child });
self
self.queue(move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.remove_parent_in_place();
}
})
}
}
impl BuildChildrenTransformExt for EntityWorldMut<'_> {
fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {
let child = self.id();
self.world_scope(|world| AddChildInPlace { child, parent }.apply(world));
self.world_scope(|world| {
world.entity_mut(parent).add_child(child);
// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.
let mut update_transform = || {
let parent = *world.get_entity(parent).ok()?.get::<GlobalTransform>()?;
let child_global = *world.get_entity(child).ok()?.get::<GlobalTransform>()?;
let mut child_entity = world.get_entity_mut(child).ok()?;
let mut child = child_entity.get_mut::<Transform>()?;
*child = child_global.reparented_to(&parent);
Some(())
};
update_transform();
});
self
}
fn remove_parent_in_place(&mut self) -> &mut Self {
let child = self.id();
self.world_scope(|world| RemoveParentInPlace { child }.apply(world));
self.world_scope(|world| {
world.entity_mut(child).remove_parent();
// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.
let mut update_transform = || {
let child_global = *world.get_entity(child).ok()?.get::<GlobalTransform>()?;
let mut child_entity = world.get_entity_mut(child).ok()?;
let mut child = child_entity.get_mut::<Transform>()?;
*child = child_global.compute_transform();
Some(())
};
update_transform();
});
self
}
}