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:
parent
4f9dc6534b
commit
9ac7e17f2e
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user