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 mutator;
|
||||||
mod reader;
|
mod reader;
|
||||||
mod registry;
|
mod registry;
|
||||||
mod send_event;
|
|
||||||
mod update;
|
mod update;
|
||||||
mod writer;
|
mod writer;
|
||||||
|
|
||||||
@ -25,7 +24,6 @@ pub use mut_iterators::{EventMutIterator, EventMutIteratorWithId};
|
|||||||
pub use mutator::EventMutator;
|
pub use mutator::EventMutator;
|
||||||
pub use reader::EventReader;
|
pub use reader::EventReader;
|
||||||
pub use registry::{EventRegistry, ShouldUpdateEvents};
|
pub use registry::{EventRegistry, ShouldUpdateEvents};
|
||||||
pub use send_event::SendEvent;
|
|
||||||
pub use update::{
|
pub use update::{
|
||||||
event_update_condition, event_update_system, signal_event_update_system, EventUpdates,
|
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,
|
change_detection::Mut,
|
||||||
component::{Component, ComponentId, ComponentInfo, Mutable},
|
component::{Component, ComponentId, ComponentInfo, Mutable},
|
||||||
entity::{Entities, Entity, EntityCloneBuilder},
|
entity::{Entities, Entity, EntityCloneBuilder},
|
||||||
event::{Event, SendEvent},
|
event::{Event, Events},
|
||||||
observer::{Observer, TriggerTargets},
|
observer::{Observer, TriggerTargets},
|
||||||
schedule::ScheduleLabel,
|
schedule::ScheduleLabel,
|
||||||
system::{input::SystemInput, SystemId},
|
system::{input::SystemInput, SystemId},
|
||||||
@ -1060,10 +1060,15 @@ impl<'w, 's> Commands<'w, 's> {
|
|||||||
/// [`EventWriter`]: crate::event::EventWriter
|
/// [`EventWriter`]: crate::event::EventWriter
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn send_event<E: Event>(&mut self, event: E) -> &mut Self {
|
pub fn send_event<E: Event>(&mut self, event: E) -> &mut Self {
|
||||||
self.queue(SendEvent {
|
#[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,
|
event,
|
||||||
#[cfg(feature = "track_change_detection")]
|
#[cfg(feature = "track_change_detection")]
|
||||||
caller: Location::caller(),
|
caller,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use crate::{Children, HierarchyEvent, Parent};
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
bundle::Bundle,
|
bundle::Bundle,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
prelude::Events,
|
event::Events,
|
||||||
system::{Commands, EntityCommands},
|
system::{Commands, EntityCommands},
|
||||||
world::{Command, EntityWorldMut, World},
|
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.
|
/// Struct for building children entities and adding them to a parent entity.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -276,7 +173,8 @@ impl Command for RemoveParent {
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct ChildBuilder<'a> {
|
pub struct ChildBuilder<'a> {
|
||||||
commands: Commands<'a, '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
|
/// 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 {
|
fn spawn(&mut self, bundle: impl Bundle) -> EntityCommands {
|
||||||
let e = self.commands.spawn(bundle);
|
let e = self.commands.spawn(bundle);
|
||||||
self.add_children.children.push(e.id());
|
self.children.push(e.id());
|
||||||
e
|
e
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_empty(&mut self) -> EntityCommands {
|
fn spawn_empty(&mut self) -> EntityCommands {
|
||||||
let e = self.commands.spawn_empty();
|
let e = self.commands.spawn_empty();
|
||||||
self.add_children.children.push(e.id());
|
self.children.push(e.id());
|
||||||
e
|
e
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_entity(&self) -> Entity {
|
fn parent_entity(&self) -> Entity {
|
||||||
self.add_children.parent
|
self.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
fn queue_command<C: Command>(&mut self, command: C) -> &mut Self {
|
fn queue_command<C: Command>(&mut self, command: C) -> &mut Self {
|
||||||
@ -431,38 +329,37 @@ impl BuildChildren for EntityCommands<'_> {
|
|||||||
let parent = self.id();
|
let parent = self.id();
|
||||||
let mut builder = ChildBuilder {
|
let mut builder = ChildBuilder {
|
||||||
commands: self.commands(),
|
commands: self.commands(),
|
||||||
add_children: AddChildren {
|
|
||||||
children: SmallVec::default(),
|
children: SmallVec::default(),
|
||||||
parent,
|
parent,
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
spawn_children(&mut builder);
|
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.");
|
panic!("Entity cannot be a child of itself.");
|
||||||
}
|
}
|
||||||
self.commands().queue(children);
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self
|
world.entity_mut(entity).add_children(&children);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_child<B: Bundle>(&mut self, bundle: B) -> &mut Self {
|
fn with_child<B: Bundle>(&mut self, bundle: B) -> &mut Self {
|
||||||
let parent = self.id();
|
|
||||||
let child = self.commands().spawn(bundle).id();
|
let child = self.commands().spawn(bundle).id();
|
||||||
self.commands().queue(AddChild { parent, child });
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self
|
world.entity_mut(entity).add_child(child);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_children(&mut self, children: &[Entity]) -> &mut Self {
|
fn add_children(&mut self, children: &[Entity]) -> &mut Self {
|
||||||
let parent = self.id();
|
let parent = self.id();
|
||||||
if children.contains(&parent) {
|
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 {
|
let children = SmallVec::<[Entity; 8]>::from_slice(children);
|
||||||
children: SmallVec::from(children),
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
parent,
|
world.entity_mut(entity).add_children(&children);
|
||||||
});
|
})
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self {
|
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self {
|
||||||
@ -470,21 +367,17 @@ impl BuildChildren for EntityCommands<'_> {
|
|||||||
if children.contains(&parent) {
|
if children.contains(&parent) {
|
||||||
panic!("Cannot insert entity as a child of itself.");
|
panic!("Cannot insert entity as a child of itself.");
|
||||||
}
|
}
|
||||||
self.commands().queue(InsertChildren {
|
let children = SmallVec::<[Entity; 8]>::from_slice(children);
|
||||||
children: SmallVec::from(children),
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
index,
|
world.entity_mut(entity).insert_children(index, &children);
|
||||||
parent,
|
})
|
||||||
});
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_children(&mut self, children: &[Entity]) -> &mut Self {
|
fn remove_children(&mut self, children: &[Entity]) -> &mut Self {
|
||||||
let parent = self.id();
|
let children = SmallVec::<[Entity; 8]>::from_slice(children);
|
||||||
self.commands().queue(RemoveChildren {
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
children: SmallVec::from(children),
|
world.entity_mut(entity).remove_children(&children);
|
||||||
parent,
|
})
|
||||||
});
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_child(&mut self, child: Entity) -> &mut Self {
|
fn add_child(&mut self, child: Entity) -> &mut Self {
|
||||||
@ -492,14 +385,15 @@ impl BuildChildren for EntityCommands<'_> {
|
|||||||
if child == parent {
|
if child == parent {
|
||||||
panic!("Cannot add entity as a child of itself.");
|
panic!("Cannot add entity as a child of itself.");
|
||||||
}
|
}
|
||||||
self.commands().queue(AddChild { child, parent });
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self
|
world.entity_mut(entity).add_child(child);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_children(&mut self) -> &mut Self {
|
fn clear_children(&mut self) -> &mut Self {
|
||||||
let parent = self.id();
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self.commands().queue(ClearChildren { parent });
|
world.entity_mut(entity).clear_children();
|
||||||
self
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_children(&mut self, children: &[Entity]) -> &mut Self {
|
fn replace_children(&mut self, children: &[Entity]) -> &mut Self {
|
||||||
@ -507,11 +401,10 @@ impl BuildChildren for EntityCommands<'_> {
|
|||||||
if children.contains(&parent) {
|
if children.contains(&parent) {
|
||||||
panic!("Cannot replace entity as a child of itself.");
|
panic!("Cannot replace entity as a child of itself.");
|
||||||
}
|
}
|
||||||
self.commands().queue(ReplaceChildren {
|
let children = SmallVec::<[Entity; 8]>::from_slice(children);
|
||||||
children: SmallVec::from(children),
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
parent,
|
world.entity_mut(entity).replace_children(&children);
|
||||||
});
|
})
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_parent(&mut self, parent: Entity) -> &mut Self {
|
fn set_parent(&mut self, parent: Entity) -> &mut Self {
|
||||||
@ -519,14 +412,15 @@ impl BuildChildren for EntityCommands<'_> {
|
|||||||
if child == parent {
|
if child == parent {
|
||||||
panic!("Cannot set parent to itself");
|
panic!("Cannot set parent to itself");
|
||||||
}
|
}
|
||||||
self.commands().queue(AddChild { child, parent });
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self
|
world.entity_mut(parent).add_child(entity);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_parent(&mut self) -> &mut Self {
|
fn remove_parent(&mut self) -> &mut Self {
|
||||||
let child = self.id();
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self.commands().queue(RemoveParent { child });
|
world.entity_mut(entity).remove_parent();
|
||||||
self
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,16 +451,7 @@ impl ChildBuild for WorldChildBuilder<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_empty(&mut self) -> EntityWorldMut {
|
fn spawn_empty(&mut self) -> EntityWorldMut {
|
||||||
let entity = self.world.spawn(Parent(self.parent)).id();
|
self.spawn(())
|
||||||
add_child_unchecked(self.world, self.parent, entity);
|
|
||||||
push_events(
|
|
||||||
self.world,
|
|
||||||
[HierarchyEvent::ChildAdded {
|
|
||||||
child: entity,
|
|
||||||
parent: self.parent,
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
self.world.entity_mut(entity)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parent_entity(&self) -> Entity {
|
fn parent_entity(&self) -> Entity {
|
||||||
@ -691,7 +576,11 @@ impl BuildChildren for EntityWorldMut<'_> {
|
|||||||
fn clear_children(&mut self) -> &mut Self {
|
fn clear_children(&mut self) -> &mut Self {
|
||||||
let parent = self.id();
|
let parent = self.id();
|
||||||
self.world_scope(|world| {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
@ -6,28 +6,10 @@ use bevy_ecs::{
|
|||||||
component::ComponentCloneHandler,
|
component::ComponentCloneHandler,
|
||||||
entity::{ComponentCloneCtx, Entity, EntityCloneBuilder},
|
entity::{ComponentCloneCtx, Entity, EntityCloneBuilder},
|
||||||
system::EntityCommands,
|
system::EntityCommands,
|
||||||
world::{Command, DeferredWorld, EntityWorldMut, World},
|
world::{DeferredWorld, EntityWorldMut, World},
|
||||||
};
|
};
|
||||||
use log::debug;
|
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
|
/// Function for despawning an entity and all its children
|
||||||
pub fn despawn_with_children_recursive(world: &mut World, entity: Entity, warn: bool) {
|
pub fn despawn_with_children_recursive(world: &mut World, entity: Entity, warn: bool) {
|
||||||
// first, make the entity's own parent forget about it
|
// 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);
|
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) {
|
fn despawn_with_children_recursive_inner(world: &mut World, entity: Entity, warn: bool) {
|
||||||
if let Some(mut children) = world.get_mut::<Children>(entity) {
|
if let Some(mut children) = world.get_mut::<Children>(entity) {
|
||||||
for e in core::mem::take(&mut children.0) {
|
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
|
/// Trait that holds functions for despawning recursively down the transform hierarchy
|
||||||
pub trait DespawnRecursiveExt {
|
pub trait DespawnRecursiveExt {
|
||||||
/// Despawns the provided entity alongside all descendants.
|
/// Despawns the provided entity alongside all descendants.
|
||||||
@ -114,33 +67,65 @@ impl DespawnRecursiveExt for EntityCommands<'_> {
|
|||||||
/// Despawns the provided entity and its children.
|
/// Despawns the provided entity and its children.
|
||||||
/// This will emit warnings for any entity that does not exist.
|
/// This will emit warnings for any entity that does not exist.
|
||||||
fn despawn_recursive(mut self) {
|
fn despawn_recursive(mut self) {
|
||||||
let entity = self.id();
|
let warn = true;
|
||||||
self.commands()
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
.queue(DespawnRecursive { entity, warn: true });
|
#[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 {
|
fn despawn_descendants(&mut self) -> &mut Self {
|
||||||
let entity = self.id();
|
let warn = true;
|
||||||
self.commands()
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
.queue(DespawnChildrenRecursive { entity, warn: true });
|
#[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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Despawns the provided entity and its children.
|
/// Despawns the provided entity and its children.
|
||||||
/// This will never emit warnings.
|
/// This will never emit warnings.
|
||||||
fn try_despawn_recursive(mut self) {
|
fn try_despawn_recursive(mut self) {
|
||||||
let entity = self.id();
|
let warn = false;
|
||||||
self.commands().queue(DespawnRecursive {
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
entity,
|
#[cfg(feature = "trace")]
|
||||||
warn: false,
|
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 {
|
fn try_despawn_descendants(&mut self) -> &mut Self {
|
||||||
let entity = self.id();
|
let warn = false;
|
||||||
self.commands().queue(DespawnChildrenRecursive {
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
entity,
|
#[cfg(feature = "trace")]
|
||||||
warn: false,
|
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
|
self
|
||||||
}
|
}
|
||||||
|
@ -204,9 +204,9 @@ mod tests {
|
|||||||
},
|
},
|
||||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||||
system::Resource,
|
system::Resource,
|
||||||
world::{Command, World},
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_hierarchy::{AddChild, Parent};
|
use bevy_hierarchy::{BuildChildren, Parent};
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
|
|
||||||
use crate::dynamic_scene::DynamicScene;
|
use crate::dynamic_scene::DynamicScene;
|
||||||
@ -271,11 +271,9 @@ mod tests {
|
|||||||
.register::<Parent>();
|
.register::<Parent>();
|
||||||
let original_parent_entity = world.spawn_empty().id();
|
let original_parent_entity = world.spawn_empty().id();
|
||||||
let original_child_entity = world.spawn_empty().id();
|
let original_child_entity = world.spawn_empty().id();
|
||||||
AddChild {
|
world
|
||||||
parent: original_parent_entity,
|
.entity_mut(original_parent_entity)
|
||||||
child: original_child_entity,
|
.add_child(original_child_entity);
|
||||||
}
|
|
||||||
.apply(&mut world);
|
|
||||||
|
|
||||||
// We then write this relationship to a new scene, and then write that scene back to the
|
// 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
|
// 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
|
// We then add the parent from the scene as a child of the original child
|
||||||
// Hierarchy should look like:
|
// Hierarchy should look like:
|
||||||
// Original Parent <- Original Child <- Scene Parent <- Scene Child
|
// Original Parent <- Original Child <- Scene Parent <- Scene Child
|
||||||
AddChild {
|
world
|
||||||
parent: original_child_entity,
|
.entity_mut(original_child_entity)
|
||||||
child: from_scene_parent_entity,
|
.add_child(from_scene_parent_entity);
|
||||||
}
|
|
||||||
.apply(&mut world);
|
|
||||||
|
|
||||||
// We then reload the scene to make sure that from_scene_parent_entity's parent component
|
// 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.
|
// 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},
|
event::{Event, EventCursor, Events},
|
||||||
reflect::AppTypeRegistry,
|
reflect::AppTypeRegistry,
|
||||||
system::Resource,
|
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_reflect::Reflect;
|
||||||
use bevy_utils::{HashMap, HashSet};
|
use bevy_utils::{HashMap, HashSet};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -382,11 +382,7 @@ impl SceneSpawner {
|
|||||||
// this case shouldn't happen anyway
|
// this case shouldn't happen anyway
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
AddChild {
|
world.entity_mut(parent).add_child(entity);
|
||||||
parent,
|
|
||||||
child: entity,
|
|
||||||
}
|
|
||||||
.apply(world);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,83 +3,19 @@
|
|||||||
|
|
||||||
use crate::prelude::{GlobalTransform, Transform};
|
use crate::prelude::{GlobalTransform, Transform};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::Entity,
|
entity::Entity,
|
||||||
system::EntityCommands,
|
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
|
/// Collection of methods similar to [`BuildChildren`], but preserving each
|
||||||
/// 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
|
|
||||||
/// entity's [`GlobalTransform`].
|
/// entity's [`GlobalTransform`].
|
||||||
pub trait BuildChildrenTransformExt {
|
pub trait BuildChildrenTransformExt {
|
||||||
/// Change this entity's parent while preserving this entity's [`GlobalTransform`]
|
/// Change this entity's parent while preserving this entity's [`GlobalTransform`]
|
||||||
/// by updating its [`Transform`].
|
/// by updating its [`Transform`].
|
||||||
///
|
///
|
||||||
/// See [`BuildChildren::set_parent`](bevy_hierarchy::BuildChildren::set_parent) for a method that doesn't update the
|
/// See [`BuildChildren::set_parent`] for a method that doesn't update the [`Transform`].
|
||||||
/// [`Transform`].
|
|
||||||
///
|
///
|
||||||
/// Note that both the hierarchy and transform updates will only execute
|
/// Note that both the hierarchy and transform updates will only execute
|
||||||
/// the next time commands are applied
|
/// the next time commands are applied
|
||||||
@ -89,38 +25,65 @@ pub trait BuildChildrenTransformExt {
|
|||||||
/// Make this entity parentless while preserving this entity's [`GlobalTransform`]
|
/// Make this entity parentless while preserving this entity's [`GlobalTransform`]
|
||||||
/// by updating its [`Transform`] to be equal to its current [`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
|
/// See [`BuildChildren::remove_parent`] for a method that doesn't update the [`Transform`].
|
||||||
/// [`Transform`].
|
|
||||||
///
|
///
|
||||||
/// Note that both the hierarchy and transform updates will only execute
|
/// Note that both the hierarchy and transform updates will only execute
|
||||||
/// the next time commands are applied
|
/// the next time commands are applied
|
||||||
/// (during [`ApplyDeferred`](bevy_ecs::schedule::ApplyDeferred)).
|
/// (during [`ApplyDeferred`](bevy_ecs::schedule::ApplyDeferred)).
|
||||||
fn remove_parent_in_place(&mut self) -> &mut Self;
|
fn remove_parent_in_place(&mut self) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildChildrenTransformExt for EntityCommands<'_> {
|
impl BuildChildrenTransformExt for EntityCommands<'_> {
|
||||||
fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {
|
fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {
|
||||||
let child = self.id();
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self.commands().queue(AddChildInPlace { child, parent });
|
if let Ok(mut entity) = world.get_entity_mut(entity) {
|
||||||
self
|
entity.set_parent_in_place(parent);
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_parent_in_place(&mut self) -> &mut Self {
|
fn remove_parent_in_place(&mut self) -> &mut Self {
|
||||||
let child = self.id();
|
self.queue(move |entity: Entity, world: &mut World| {
|
||||||
self.commands().queue(RemoveParentInPlace { child });
|
if let Ok(mut entity) = world.get_entity_mut(entity) {
|
||||||
self
|
entity.remove_parent_in_place();
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildChildrenTransformExt for EntityWorldMut<'_> {
|
impl BuildChildrenTransformExt for EntityWorldMut<'_> {
|
||||||
fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {
|
fn set_parent_in_place(&mut self, parent: Entity) -> &mut Self {
|
||||||
let child = self.id();
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_parent_in_place(&mut self) -> &mut Self {
|
fn remove_parent_in_place(&mut self) -> &mut Self {
|
||||||
let child = self.id();
|
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
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user