Skip to content
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

Extend cloning functionality and add convenience methods to EntityWorldMut and EntityCommands #16826

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gah more panics :( Not your problem: this needs a holistic solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do have another PR for that :P (not holistic, just commands). Not sure how it'll interact with work in the fallible systems area though

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
Loading