Skip to content

Commit 9f1577e

Browse files
committed
Add CloneBundle command
1 parent 98938a8 commit 9f1577e

File tree

1 file changed

+147
-0
lines changed
  • crates/bevy_ecs/src/system/commands

1 file changed

+147
-0
lines changed

crates/bevy_ecs/src/system/commands/mod.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,105 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
548548
self
549549
}
550550

551+
/// Clones a [`Bundle`] to a target entity.
552+
///
553+
/// # Example
554+
///
555+
/// ```
556+
/// # use bevy_ecs::prelude::*;
557+
/// #
558+
/// # #[derive(Component, Clone)]
559+
/// # struct Dummy;
560+
/// #
561+
/// # #[derive(Bundle, Clone)]
562+
/// # struct Characteristics {
563+
/// # _dummy: Dummy
564+
/// # }
565+
/// #
566+
/// # #[derive(Component)]
567+
/// # struct Offspring { entity: Entity }
568+
/// #
569+
/// fn duplicate(mut commands: Commands, query: Query<(Entity, &Offspring)>) {
570+
/// for (source, Offspring { entity: target }) in query.iter() {
571+
/// commands.entity(source).clone_bundle_to::<Characteristics>(*target);
572+
/// }
573+
/// }
574+
/// ```
575+
pub fn clone_bundle_to<T>(&mut self, target: Entity) -> &mut Self
576+
where
577+
T: Bundle + Clone,
578+
{
579+
assert!(
580+
self.commands.entities.contains(target),
581+
"Attempting to clone from entity {:?} to entity {:?}, which doesn't exist.",
582+
self.entity,
583+
target
584+
);
585+
self.commands.add(CloneBundle::<T> {
586+
source: self.entity,
587+
target,
588+
_bundle: PhantomData,
589+
});
590+
self
591+
}
592+
593+
/// Clones a [`Component`] to a target entity.
594+
///
595+
/// # Example
596+
///
597+
/// ```
598+
/// # use bevy_ecs::prelude::*;
599+
/// #
600+
/// # #[derive(Component, Clone)]
601+
/// # struct Infected;
602+
/// #
603+
/// # #[derive(Component)]
604+
/// # struct Nearest { entity: Entity }
605+
/// #
606+
/// fn contagion(mut commands: Commands, query: Query<(Entity, &Nearest), With<Infected>>) {
607+
/// for (source, Nearest { entity: target }) in query.iter() {
608+
/// commands.entity(source).clone_to::<Infected>(*target);
609+
/// }
610+
/// }
611+
/// ```
612+
pub fn clone_to<C>(&mut self, target: Entity) -> &mut Self
613+
where
614+
C: Component + Clone,
615+
{
616+
self.clone_bundle_to::<(C,)>(target)
617+
}
618+
619+
/// Clones a [`Bundle`] from a source entity.
620+
///
621+
/// See [`clone_bundle_to`](EntityCommands::clone_bundle_to).
622+
pub fn clone_bundle_from<T>(&mut self, source: Entity) -> &mut Self
623+
where
624+
T: Bundle + Clone,
625+
{
626+
assert!(
627+
self.commands.entities.contains(source),
628+
"Attempting to clone from entity {:?} to entity {:?}, which doesn't exist.",
629+
source,
630+
self.entity
631+
);
632+
self.commands.add(CloneBundle::<T> {
633+
source,
634+
target: self.entity,
635+
_bundle: PhantomData,
636+
});
637+
self
638+
}
639+
640+
/// Clones a [`Component`] from a source entity.
641+
///
642+
/// See [`clone_to`](EntityCommands::clone_to)
643+
pub fn clone_from<C>(&mut self, source: Entity) -> &mut Self
644+
where
645+
C: Component + Clone,
646+
{
647+
self.clone_bundle_from::<(C,)>(source)
648+
}
649+
551650
/// Despawns the entity.
552651
///
553652
/// See [`World::despawn`] for more details.
@@ -692,6 +791,54 @@ where
692791
}
693792
}
694793

794+
pub struct CloneBundle<T> {
795+
pub source: Entity,
796+
pub target: Entity,
797+
_bundle: PhantomData<T>,
798+
}
799+
800+
impl<T> CloneBundle<T> {
801+
/// Creates a new [`CloneBundle`] with given source and target IDs.
802+
pub fn new(source: Entity, target: Entity) -> Self {
803+
Self {
804+
source,
805+
target,
806+
_bundle: PhantomData,
807+
}
808+
}
809+
}
810+
811+
impl<T> Command for CloneBundle<T>
812+
where
813+
T: Bundle + Clone + 'static,
814+
{
815+
fn write(self, world: &mut World) {
816+
let mut source_mut = if let Some(some) = world.get_entity_mut(self.source) {
817+
some
818+
} else {
819+
panic!("Could not clone a bundle (of type `{}`) from entity {:?} because it doesn't exist in this World.\n\
820+
If this command was added to a newly spawned entity, ensure that you have not despawned that entity within the same stage.\n\
821+
This may have occurred due to system order ambiguity, or if the spawning system has multiple command buffers", std::any::type_name::<T>(), self.source);
822+
};
823+
824+
let bundle = if let Some(some) = source_mut.remove_bundle::<T>() {
825+
some
826+
} else {
827+
return;
828+
};
829+
source_mut.insert_bundle(bundle.clone());
830+
831+
let mut target_mut = if let Some(some) = world.get_entity_mut(self.target) {
832+
some
833+
} else {
834+
panic!("Could not clone a bundle (of type `{}`) into entity {:?} because it doesn't exist in this World.\n\
835+
If this command was added to a newly spawned entity, ensure that you have not despawned that entity within the same stage.\n\
836+
This may have occurred due to system order ambiguity, or if the spawning system has multiple command buffers", std::any::type_name::<T>(), self.source);
837+
};
838+
target_mut.insert_bundle(bundle);
839+
}
840+
}
841+
695842
#[derive(Debug)]
696843
pub struct Insert<T> {
697844
pub entity: Entity,

0 commit comments

Comments
 (0)