Skip to content

Commit

Permalink
Move clone_entity commands to EntityCommands (#16672)
Browse files Browse the repository at this point in the history
## Objective

I was resolving a conflict between #16132 and my PR #15929 and thought
the `clone_entity` commands made more sense in `EntityCommands`.

## Solution

Moved `Commands::clone_entity` to `EntityCommands::clone`, moved
`Commands::clone_entity_with` to `EntityCommands::clone_with`.

## Testing

Ran the two tests that used the old methods.

## Showcase

```
// Create a new entity and keep its EntityCommands.
let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));

// Create a clone of the first entity
let mut entity_clone = entity.clone();
```

The only potential downside is that the method name is now the same as
the one from the `Clone` trait. `EntityCommands` doesn't implement
`Clone` though, so there's no actual conflict.

Maybe I'm biased because this'll work better with my PR, but I think the
UX is nicer regardless.
  • Loading branch information
JaySpruce authored Dec 6, 2024
1 parent 10e3cc7 commit d0afdc6
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 65 deletions.
141 changes: 78 additions & 63 deletions crates/bevy_ecs/src/system/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,69 +272,6 @@ impl<'w, 's> Commands<'w, 's> {
}
}

/// Clones an entity and allows configuring cloning behavior using [`EntityCloneBuilder`], returning [`EntityCommands`] of the cloned entity.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new entity and retrieve its id.
/// let entity = commands.spawn((ComponentA(10), ComponentB(20))).id();
///
/// // Create a clone of the first entity, but without ComponentB
/// let entity_clone = commands.clone_entity_with(entity, |builder| {
/// builder.deny::<ComponentB>();
/// }).id();
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
pub fn clone_entity_with(
&mut self,
entity: Entity,
f: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> EntityCommands<'_> {
let cloned_entity = self.spawn_empty().id();
self.queue(move |world: &mut World| {
let mut builder = EntityCloneBuilder::new(world);
f(&mut builder);
builder.clone_entity(entity, cloned_entity);
});
EntityCommands {
commands: self.reborrow(),
entity: cloned_entity,
}
}

/// Clones an entity and returns [`EntityCommands`] of the cloned entity.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new entity and retrieve its id.
/// let entity = commands.spawn((ComponentA(10), ComponentB(20))).id();
///
/// // Create a clone of the first entity
/// let entity_clone = commands.clone_entity(entity).id();
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
pub fn clone_entity(&mut self, entity: Entity) -> EntityCommands<'_> {
self.clone_entity_with(entity, |_| {})
}

/// Reserves a new empty [`Entity`] to be spawned, and returns its corresponding [`EntityCommands`].
///
/// See [`World::spawn_empty`] for more details.
Expand Down Expand Up @@ -1780,6 +1717,73 @@ impl<'a> EntityCommands<'a> {
) -> &mut Self {
self.queue(observe(system))
}

/// Clones an entity and returns the [`EntityCommands`] of the clone.
///
/// # Panics
///
/// The command will panic when applied if the original entity does not exist.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new entity and keep its EntityCommands.
/// let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
///
/// // Create a clone of the first entity
/// let entity_clone = entity.clone();
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
pub fn clone(&mut self) -> EntityCommands<'_> {
self.clone_with(|_| {})
}

/// Clones an entity and allows configuring cloning behavior using [`EntityCloneBuilder`],
/// returning the [`EntityCommands`] of the clone.
///
/// # Panics
///
/// The command will panic when applied if the original entity does not exist.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create a new entity and keep its EntityCommands.
/// let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
///
/// // Create a clone of the first entity, but without ComponentB
/// let entity_clone = entity.clone_with(|builder| {
/// builder.deny::<ComponentB>();
/// });
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
pub fn clone_with(
&mut self,
f: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> EntityCommands<'_> {
let entity_clone = self.commands().spawn_empty().id();
self.queue(clone_entity_with(entity_clone, f));
EntityCommands {
commands: self.commands_mut().reborrow(),
entity: entity_clone,
}
}
}

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

fn clone_entity_with(
entity_clone: Entity,
f: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> impl EntityCommand {
move |entity: Entity, world: &mut World| {
let mut builder = EntityCloneBuilder::new(world);
f(&mut builder);
builder.clone_entity(entity, entity_clone);
}
}

#[cfg(test)]
#[allow(clippy::float_cmp, clippy::approx_constant)]
mod tests {
Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_hierarchy/src/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,8 @@ mod tests {
})
.id();
let e_clone = commands
.clone_entity_with(e, |builder| {
.entity(e)
.clone_with(|builder| {
builder.recursive(true);
})
.id();
Expand Down Expand Up @@ -481,7 +482,8 @@ mod tests {
let parent = commands.spawn_empty().add_child(child).id();

let child_clone = commands
.clone_entity_with(child, |builder| {
.entity(child)
.clone_with(|builder| {
builder.as_child(true);
})
.id();
Expand Down

0 comments on commit d0afdc6

Please sign in to comment.