Skip to content

Commit

Permalink
add clone_components, move_components, and variants
Browse files Browse the repository at this point in the history
  • Loading branch information
JaySpruce committed Dec 15, 2024
1 parent 6178ce9 commit 1d6e8d1
Show file tree
Hide file tree
Showing 2 changed files with 467 additions and 4 deletions.
162 changes: 159 additions & 3 deletions crates/bevy_ecs/src/system/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1738,7 +1738,7 @@ impl<'a> EntityCommands<'a> {
self.queue(observe(system))
}

/// Clones an entity and returns the [`EntityCommands`] of the clone.
/// Spawns a clone of this entity and returns the [`EntityCommands`] of the clone.
///
/// The clone will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
Expand Down Expand Up @@ -1772,8 +1772,8 @@ impl<'a> EntityCommands<'a> {
self.clone_and_spawn_with(|_| {})
}

/// Clones an entity and allows configuring cloning behavior using [`EntityCloneBuilder`],
/// returning the [`EntityCommands`] of the clone.
/// Spawns a clone of this entity and allows configuring cloning behavior
/// using [`EntityCloneBuilder`], returning the [`EntityCommands`] of the clone.
///
/// By default, the clone will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
Expand All @@ -1782,6 +1782,8 @@ impl<'a> EntityCommands<'a> {
/// To only include specific components, use [`EntityCloneBuilder::deny_all`]
/// followed by [`EntityCloneBuilder::allow`].
///
/// See the methods on [`EntityCloneBuilder`] for more options.
///
/// # Panics
///
/// The command will panic when applied if the original entity does not exist.
Expand Down Expand Up @@ -1817,6 +1819,95 @@ impl<'a> EntityCommands<'a> {
entity: entity_clone,
}
}

/// Clones the specified components of this entity and inserts them into another entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// # Panics
///
/// The command will panic when applied if either of the entities do not exist.
pub fn clone_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.queue(clone_components::<B>(target))
}

/// Clones the specified components of this entity with those components' required components
/// and inserts them into another entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// # Panics
///
/// The command will panic when applied if either of the entities do not exist.
pub fn clone_components_with_requires<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.queue(clone_components_with_requires::<B>(target))
}

/// Clones the given components of this entity and inserts them into another entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// You should prefer to use the typed API [`EntityCommands::clone_components`] where possible.
///
/// # Panics
///
/// The command will panic when applied if either of the entities do not exist.
pub fn clone_components_by_id(
&mut self,
target: Entity,
ids: impl IntoIterator<Item = ComponentId> + Send + 'static,
) -> &mut Self {
self.queue(clone_components_by_id(target, ids))
}

/// Clones the specified components of this entity and inserts them into another entity,
/// then removes the components from this entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// # Panics
///
/// The command will panic when applied if either of the entities do not exist.
pub fn move_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.queue(move_components::<B>(target))
}

/// Clones the specified components of this entity with those components' required components,
/// inserts them into another entity, then removes the components from this entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// # Panics
///
/// The command will panic when applied if either of the entities do not exist.
pub fn move_components_with_requires<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.queue(move_components_with_requires::<B>(target))
}

/// Clones the given components of this entity and inserts them into another entity,
/// then removes the components from this entity.
///
/// Components can only be cloned if they implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// You should prefer to use the typed API [`EntityCommands::clone_components`] where possible.
///
/// # Panics
///
/// The command will panic when applied if either of the entities do not exist,
/// or if any of the provided [`ComponentId`]s do not exist.
pub fn move_components_by_id(
&mut self,
target: Entity,
ids: impl IntoIterator<Item = ComponentId> + Clone + Send + 'static,
) -> &mut Self {
self.queue(move_components_by_id(target, ids))
}
}

/// A wrapper around [`EntityCommands`] with convenience methods for working with a specified component type.
Expand Down Expand Up @@ -2291,6 +2382,7 @@ fn observe<E: Event, B: Bundle, M>(
}
}

/// An [`EntityCommand`] that clones an entity and allows configuring cloning behavior.
fn clone_and_spawn_with(
entity_clone: Entity,
f: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
Expand All @@ -2302,6 +2394,70 @@ fn clone_and_spawn_with(
}
}

/// An [`EntityCommand`] that clones the specified components into another entity.
fn clone_components<B: Bundle>(target: Entity) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.clone_components::<B>(target);
}
}
}

/// An [`EntityCommand`] that clones the specified components with their required components
/// into another entity.
fn clone_components_with_requires<B: Bundle>(target: Entity) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.clone_components_with_requires::<B>(target);
}
}
}

/// An [`EntityCommand`] that clones the given components into another entity.
fn clone_components_by_id(
target: Entity,
ids: impl IntoIterator<Item = ComponentId> + Send + 'static,
) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.clone_components_by_id(target, ids);
}
}
}

/// An [`EntityCommand`] that clones the specified components into another entity
/// and removes them from the original entity.
fn move_components<B: Bundle>(target: Entity) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.move_components::<B>(target);
}
}
}

/// An [`EntityCommand`] that clones the specified components with their required components
/// into another entity and removes them from the original entity.
fn move_components_with_requires<B: Bundle>(target: Entity) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.move_components_with_requires::<B>(target);
}
}
}

/// An [`EntityCommand`] that clones the given components into another entity
/// and removes them from the original entity.
fn move_components_by_id(
target: Entity,
ids: impl IntoIterator<Item = ComponentId> + Clone + Send + 'static,
) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.move_components_by_id(target, ids);
}
}
}

#[cfg(test)]
#[allow(clippy::float_cmp, clippy::approx_constant)]
mod tests {
Expand Down
Loading

0 comments on commit 1d6e8d1

Please sign in to comment.