diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 7d3f541dab930..084a74e2f6897 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -548,6 +548,105 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> { self } + /// Clones a [`Bundle`] to a target entity. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// # #[derive(Component, Clone)] + /// # struct Dummy; + /// # + /// # #[derive(Bundle, Clone)] + /// # struct Characteristics { + /// # _dummy: Dummy + /// # } + /// # + /// # #[derive(Component)] + /// # struct Offspring { entity: Entity } + /// # + /// fn duplicate(mut commands: Commands, query: Query<(Entity, &Offspring)>) { + /// for (source, Offspring { entity: target }) in query.iter() { + /// commands.entity(source).clone_bundle_to::(*target); + /// } + /// } + /// ``` + pub fn clone_bundle_to(&mut self, target: Entity) -> &mut Self + where + T: Bundle + Clone, + { + assert!( + self.commands.entities.contains(target), + "Attempting to clone from entity {:?} to entity {:?}, which doesn't exist.", + self.entity, + target + ); + self.commands.add(CloneBundle:: { + source: self.entity, + target, + _bundle: PhantomData, + }); + self + } + + /// Clones a [`Component`] to a target entity. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// # #[derive(Component, Clone)] + /// # struct Infected; + /// # + /// # #[derive(Component)] + /// # struct Nearest { entity: Entity } + /// # + /// fn contagion(mut commands: Commands, query: Query<(Entity, &Nearest), With>) { + /// for (source, Nearest { entity: target }) in query.iter() { + /// commands.entity(source).clone_to::(*target); + /// } + /// } + /// ``` + pub fn clone_to(&mut self, target: Entity) -> &mut Self + where + C: Component + Clone, + { + self.clone_bundle_to::<(C,)>(target) + } + + /// Clones a [`Bundle`] from a source entity. + /// + /// See [`clone_bundle_to`](EntityCommands::clone_bundle_to). + pub fn clone_bundle_from(&mut self, source: Entity) -> &mut Self + where + T: Bundle + Clone, + { + assert!( + self.commands.entities.contains(source), + "Attempting to clone from entity {:?} to entity {:?}, which doesn't exist.", + source, + self.entity + ); + self.commands.add(CloneBundle:: { + source, + target: self.entity, + _bundle: PhantomData, + }); + self + } + + /// Clones a [`Component`] from a source entity. + /// + /// See [`clone_to`](EntityCommands::clone_to) + pub fn clone_from(&mut self, source: Entity) -> &mut Self + where + C: Component + Clone, + { + self.clone_bundle_from::<(C,)>(source) + } + /// Despawns the entity. /// /// See [`World::despawn`] for more details. @@ -692,6 +791,54 @@ where } } +pub struct CloneBundle { + pub source: Entity, + pub target: Entity, + _bundle: PhantomData, +} + +impl CloneBundle { + /// Creates a new [`CloneBundle`] with given source and target IDs. + pub fn new(source: Entity, target: Entity) -> Self { + Self { + source, + target, + _bundle: PhantomData, + } + } +} + +impl Command for CloneBundle +where + T: Bundle + Clone + 'static, +{ + fn write(self, world: &mut World) { + let mut source_mut = if let Some(some) = world.get_entity_mut(self.source) { + some + } else { + panic!("Could not clone a bundle (of type `{}`) from entity {:?} because it doesn't exist in this World.\n\ + If this command was added to a newly spawned entity, ensure that you have not despawned that entity within the same stage.\n\ + This may have occurred due to system order ambiguity, or if the spawning system has multiple command buffers", std::any::type_name::(), self.source); + }; + + let bundle = if let Some(some) = source_mut.remove_bundle::() { + some + } else { + return; + }; + source_mut.insert_bundle(bundle.clone()); + + let mut target_mut = if let Some(some) = world.get_entity_mut(self.target) { + some + } else { + panic!("Could not clone a bundle (of type `{}`) into entity {:?} because it doesn't exist in this World.\n\ + If this command was added to a newly spawned entity, ensure that you have not despawned that entity within the same stage.\n\ + This may have occurred due to system order ambiguity, or if the spawning system has multiple command buffers", std::any::type_name::(), self.source); + }; + target_mut.insert_bundle(bundle); + } +} + #[derive(Debug)] pub struct Insert { pub entity: Entity,