-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Add CloneBundle command #3820
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CloneBundle command #3820
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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::<Characteristics>(*target); | ||
/// } | ||
/// } | ||
/// ``` | ||
pub fn clone_bundle_to<T>(&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::<T> { | ||
source: self.entity, | ||
target, | ||
_bundle: PhantomData, | ||
}); | ||
self | ||
} | ||
|
||
/// Clones a [`Component`] to a target entity. | ||
/// | ||
/// # Example | ||
/// | ||
/// ``` | ||
/// # use bevy_ecs::prelude::*; | ||
/// # | ||
/// # #[derive(Component, Clone)] | ||
/// # struct Infected; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would be much better motivated if it stored a value. Perhaps There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @alice-i-cecile At moment I've followed the other examples and hidden the |
||
/// # | ||
/// # #[derive(Component)] | ||
/// # struct Nearest { entity: Entity } | ||
/// # | ||
/// fn contagion(mut commands: Commands, query: Query<(Entity, &Nearest), With<Infected>>) { | ||
/// for (source, Nearest { entity: target }) in query.iter() { | ||
/// commands.entity(source).clone_to::<Infected>(*target); | ||
/// } | ||
/// } | ||
/// ``` | ||
pub fn clone_to<C>(&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<T>(&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::<T> { | ||
source, | ||
target: self.entity, | ||
_bundle: PhantomData, | ||
}); | ||
self | ||
} | ||
|
||
/// Clones a [`Component`] from a source entity. | ||
/// | ||
/// See [`clone_to`](EntityCommands::clone_to) | ||
pub fn clone_from<C>(&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<T> { | ||
pub source: Entity, | ||
pub target: Entity, | ||
_bundle: PhantomData<T>, | ||
} | ||
|
||
impl<T> CloneBundle<T> { | ||
/// Creates a new [`CloneBundle`] with given source and target IDs. | ||
pub fn new(source: Entity, target: Entity) -> Self { | ||
Self { | ||
source, | ||
target, | ||
_bundle: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
impl<T> Command for CloneBundle<T> | ||
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::<T>(), self.source); | ||
}; | ||
|
||
let bundle = if let Some(some) = source_mut.remove_bundle::<T>() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will trigger "removed events" (in |
||
some | ||
} else { | ||
return; | ||
}; | ||
source_mut.insert_bundle(bundle.clone()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will trigger "added" and "changed" events for each component in the bundle, which is undesirable for a clone operation. |
||
|
||
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::<T>(), self.source); | ||
}; | ||
target_mut.insert_bundle(bundle); | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct Insert<T> { | ||
pub entity: Entity, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO we should store multiple actual value-ful components here rather than fussing with
Dummy
. Just toss in strength / dexterity / intelligence perhaps?