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

## Objective

Thanks to @eugineerd's work on entity cloning (#16132), we now have a
robust way to copy components between entities. We can extend this to
implement some useful functionality that would have been more
complicated before.

Closes #15350.

## Solution

`EntityCloneBuilder` now automatically includes required components
alongside any component added/removed from the component filter.

Added the following methods to `EntityCloneBuilder`:
- `move_components`
- `without_required_components`

Added the following methods to `EntityWorldMut` and `EntityCommands`:
- `clone_with`
- `clone_components`
- `move_components`

Also added `clone_and_spawn` and `clone_and_spawn_with` to
`EntityWorldMut` (`EntityCommands` already had them).

## Showcase

```
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B));
assert_eq!(world.entity(entity_b).get::<B>(), None);
world.entity_mut(entity_a).clone_components::<B>(entity_b);
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B));
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B));

assert_eq!(world.entity(entity_a).get::<C>(), Some(&C(5)));
assert_eq!(world.entity(entity_b).get::<C>(), None);
world.entity_mut(entity_a).move_components::<C>(entity_b);
assert_eq!(world.entity(entity_a).get::<C>(), None);
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(5)));
```
This commit is contained in:
JaySpruce 2024-12-16 13:37:32 -06:00 committed by GitHub
parent 74e793d1e1
commit 5a94beb239
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 489 additions and 70 deletions

View File

@ -18,6 +18,7 @@ pub struct EntityCloner {
filter_allows_components: bool,
filter: Arc<HashSet<ComponentId>>,
clone_handlers_overrides: Arc<HashMap<ComponentId, ComponentCloneHandler>>,
move_components: bool,
}
impl EntityCloner {
@ -35,17 +36,21 @@ impl EntityCloner {
.filter(|id| self.is_cloning_allowed(id)),
);
for component in components {
for component in &components {
let global_handlers = world.components().get_component_clone_handlers();
let handler = match self.clone_handlers_overrides.get(&component) {
None => global_handlers.get_handler(component),
let handler = match self.clone_handlers_overrides.get(component) {
None => global_handlers.get_handler(*component),
Some(ComponentCloneHandler::Default) => global_handlers.get_default_handler(),
Some(ComponentCloneHandler::Ignore) => component_clone_ignore,
Some(ComponentCloneHandler::Custom(handler)) => *handler,
};
self.component_id = Some(component);
self.component_id = Some(*component);
(handler)(&mut world.into(), self);
}
if self.move_components {
world.entity_mut(self.source).remove_by_ids(&components);
}
}
fn is_cloning_allowed(&self, component: &ComponentId) -> bool {
@ -145,6 +150,8 @@ pub struct EntityCloneBuilder<'w> {
filter_allows_components: bool,
filter: HashSet<ComponentId>,
clone_handlers_overrides: HashMap<ComponentId, ComponentCloneHandler>,
attach_required_components: bool,
move_components: bool,
}
impl<'w> EntityCloneBuilder<'w> {
@ -155,6 +162,8 @@ impl<'w> EntityCloneBuilder<'w> {
filter_allows_components: false,
filter: Default::default(),
clone_handlers_overrides: Default::default(),
attach_required_components: true,
move_components: false,
}
}
@ -165,6 +174,7 @@ impl<'w> EntityCloneBuilder<'w> {
filter_allows_components,
filter,
clone_handlers_overrides,
move_components,
..
} = self;
@ -175,29 +185,49 @@ impl<'w> EntityCloneBuilder<'w> {
filter_allows_components,
filter: Arc::new(filter),
clone_handlers_overrides: Arc::new(clone_handlers_overrides),
move_components,
}
.clone_entity(world);
world.flush_commands();
}
/// By default, any components allowed/denied through the filter will automatically
/// allow/deny all of their required components.
///
/// This method allows for a scoped mode where any changes to the filter
/// will not involve required components.
pub fn without_required_components(
&mut self,
builder: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> &mut Self {
self.attach_required_components = false;
builder(self);
self.attach_required_components = true;
self
}
/// Sets whether the cloner should remove any components that were cloned,
/// effectively moving them from the source entity to the target.
///
/// This is disabled by default.
///
/// The setting only applies to components that are allowed through the filter
/// at the time [`EntityCloneBuilder::clone_entity`] is called.
pub fn move_components(&mut self, enable: bool) -> &mut Self {
self.move_components = enable;
self
}
/// Adds all components of the bundle to the list of components to clone.
///
/// Note that all components are allowed by default, to clone only explicitly allowed components make sure to call
/// [`deny_all`](`Self::deny_all`) before calling any of the `allow` methods.
pub fn allow<T: Bundle>(&mut self) -> &mut Self {
if self.filter_allows_components {
T::get_component_ids(self.world.components(), &mut |id| {
if let Some(id) = id {
self.filter.insert(id);
}
});
} else {
T::get_component_ids(self.world.components(), &mut |id| {
if let Some(id) = id {
self.filter.remove(&id);
}
});
let bundle = self.world.register_bundle::<T>();
let ids = bundle.explicit_components().to_owned();
for id in ids {
self.filter_allow(id);
}
self
}
@ -207,12 +237,8 @@ impl<'w> EntityCloneBuilder<'w> {
/// Note that all components are allowed by default, to clone only explicitly allowed components make sure to call
/// [`deny_all`](`Self::deny_all`) before calling any of the `allow` methods.
pub fn allow_by_ids(&mut self, ids: impl IntoIterator<Item = ComponentId>) -> &mut Self {
if self.filter_allows_components {
self.filter.extend(ids);
} else {
ids.into_iter().for_each(|id| {
self.filter.remove(&id);
});
for id in ids {
self.filter_allow(id);
}
self
}
@ -222,15 +248,10 @@ impl<'w> EntityCloneBuilder<'w> {
/// Note that all components are allowed by default, to clone only explicitly allowed components make sure to call
/// [`deny_all`](`Self::deny_all`) before calling any of the `allow` methods.
pub fn allow_by_type_ids(&mut self, ids: impl IntoIterator<Item = TypeId>) -> &mut Self {
let ids = ids
.into_iter()
.filter_map(|id| self.world.components().get_id(id));
if self.filter_allows_components {
self.filter.extend(ids);
} else {
ids.into_iter().for_each(|id| {
self.filter.remove(&id);
});
for type_id in ids {
if let Some(id) = self.world.components().get_id(type_id) {
self.filter_allow(id);
}
}
self
}
@ -244,45 +265,28 @@ impl<'w> EntityCloneBuilder<'w> {
/// Disallows all components of the bundle from being cloned.
pub fn deny<T: Bundle>(&mut self) -> &mut Self {
if self.filter_allows_components {
T::get_component_ids(self.world.components(), &mut |id| {
if let Some(id) = id {
self.filter.remove(&id);
}
});
} else {
T::get_component_ids(self.world.components(), &mut |id| {
if let Some(id) = id {
self.filter.insert(id);
}
});
let bundle = self.world.register_bundle::<T>();
let ids = bundle.explicit_components().to_owned();
for id in ids {
self.filter_deny(id);
}
self
}
/// Extends the list of components that shouldn't be cloned.
pub fn deny_by_ids(&mut self, ids: impl IntoIterator<Item = ComponentId>) -> &mut Self {
if self.filter_allows_components {
ids.into_iter().for_each(|id| {
self.filter.remove(&id);
});
} else {
self.filter.extend(ids);
for id in ids {
self.filter_deny(id);
}
self
}
/// Extends the list of components that shouldn't be cloned by type ids.
pub fn deny_by_type_ids(&mut self, ids: impl IntoIterator<Item = TypeId>) -> &mut Self {
let ids = ids
.into_iter()
.filter_map(|id| self.world.components().get_id(id));
if self.filter_allows_components {
ids.into_iter().for_each(|id| {
self.filter.remove(&id);
});
} else {
self.filter.extend(ids);
for type_id in ids {
if let Some(id) = self.world.components().get_id(type_id) {
self.filter_deny(id);
}
}
self
}
@ -315,11 +319,52 @@ impl<'w> EntityCloneBuilder<'w> {
}
self
}
/// Helper function that allows a component through the filter.
fn filter_allow(&mut self, id: ComponentId) {
if self.filter_allows_components {
self.filter.insert(id);
} else {
self.filter.remove(&id);
}
if self.attach_required_components {
if let Some(info) = self.world.components().get_info(id) {
for required_id in info.required_components().iter_ids() {
if self.filter_allows_components {
self.filter.insert(required_id);
} else {
self.filter.remove(&required_id);
}
}
}
}
}
/// Helper function that disallows a component through the filter.
fn filter_deny(&mut self, id: ComponentId) {
if self.filter_allows_components {
self.filter.remove(&id);
} else {
self.filter.insert(id);
}
if self.attach_required_components {
if let Some(info) = self.world.components().get_info(id) {
for required_id in info.required_components().iter_ids() {
if self.filter_allows_components {
self.filter.remove(&required_id);
} else {
self.filter.insert(required_id);
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use crate::{self as bevy_ecs, component::Component, entity::EntityCloneBuilder, world::World};
use bevy_ecs_macros::require;
#[cfg(feature = "bevy_reflect")]
#[test]
@ -520,4 +565,34 @@ mod tests {
assert!(world.get::<B>(e_clone).is_none());
assert!(world.get::<C>(e_clone).is_none());
}
#[test]
fn clone_entity_with_required_components() {
#[derive(Component, Clone, PartialEq, Debug)]
#[require(B)]
struct A;
#[derive(Component, Clone, PartialEq, Debug, Default)]
#[require(C(|| C(5)))]
struct B;
#[derive(Component, Clone, PartialEq, Debug)]
struct C(u32);
let mut world = World::default();
let e = world.spawn(A).id();
let e_clone = world.spawn_empty().id();
let mut builder = EntityCloneBuilder::new(&mut world);
builder.deny_all();
builder.without_required_components(|builder| {
builder.allow::<B>();
});
builder.clone_entity(e, e_clone);
assert_eq!(world.entity(e_clone).get::<A>(), None);
assert_eq!(world.entity(e_clone).get::<B>(), Some(&B));
assert_eq!(world.entity(e_clone).get::<C>(), Some(&C(5)));
}
}

View File

@ -1738,7 +1738,53 @@ impl<'a> EntityCommands<'a> {
self.queue(observe(system))
}
/// Clones an entity and returns the [`EntityCommands`] of the clone.
/// Clones parts of an entity (components, observers, etc.) onto another entity,
/// configured through [`EntityCloneBuilder`].
///
/// By default, the other entity will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// Configure through [`EntityCloneBuilder`] as follows:
/// ```
/// # use bevy_ecs::prelude::*;
///
/// #[derive(Component, Clone)]
/// struct ComponentA(u32);
/// #[derive(Component, Clone)]
/// struct ComponentB(u32);
///
/// fn example_system(mut commands: Commands) {
/// // Create an empty entity
/// let target = commands.spawn_empty().id();
///
/// // Create a new entity and keep its EntityCommands
/// let mut entity = commands.spawn((ComponentA(10), ComponentB(20)));
///
/// // Clone only ComponentA onto the target
/// entity.clone_with(target, |builder| {
/// builder.deny::<ComponentB>();
/// });
/// }
/// # bevy_ecs::system::assert_is_system(example_system);
/// ```
///
/// See the following for more options:
/// - [`EntityCloneBuilder`]
/// - [`CloneEntityWithObserversExt`](crate::observer::CloneEntityWithObserversExt)
/// - `CloneEntityHierarchyExt`
///
/// # Panics
///
/// The command will panic when applied if either of the entities do not exist.
pub fn clone_with(
&mut self,
target: Entity,
config: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> &mut Self {
self.queue(clone_with(target, config))
}
/// 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).
@ -1772,8 +1818,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).
@ -1782,6 +1828,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.
@ -1808,15 +1856,40 @@ impl<'a> EntityCommands<'a> {
/// # bevy_ecs::system::assert_is_system(example_system);
pub fn clone_and_spawn_with(
&mut self,
f: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
config: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> EntityCommands<'_> {
let entity_clone = self.commands().spawn_empty().id();
self.queue(clone_and_spawn_with(entity_clone, f));
self.queue(clone_with(entity_clone, config));
EntityCommands {
commands: self.commands_mut().reborrow(),
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.
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 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))
}
}
/// A wrapper around [`EntityCommands`] with convenience methods for working with a specified component type.
@ -2291,14 +2364,34 @@ fn observe<E: Event, B: Bundle, M>(
}
}
fn clone_and_spawn_with(
entity_clone: Entity,
f: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
/// An [`EntityCommand`] that clones an entity with configurable cloning behavior.
fn clone_with(
target: Entity,
config: 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);
if let Ok(mut entity) = world.get_entity_mut(entity) {
entity.clone_with(target, config);
}
}
}
/// 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 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);
}
}
}

View File

@ -3,7 +3,7 @@ use crate::{
bundle::{Bundle, BundleId, BundleInfo, BundleInserter, DynamicBundle, InsertMode},
change_detection::MutUntyped,
component::{Component, ComponentId, ComponentTicks, Components, Mutable, StorageType},
entity::{Entities, Entity, EntityLocation},
entity::{Entities, Entity, EntityCloneBuilder, EntityLocation},
event::Event,
observer::Observer,
query::{Access, ReadOnlyQueryData},
@ -1819,6 +1819,31 @@ impl<'w> EntityWorldMut<'w> {
self
}
/// Removes a dynamic bundle from the entity if it exists.
///
/// You should prefer to use the typed API [`EntityWorldMut::remove`] where possible.
///
/// # Panics
///
/// Panics if any of the provided [`ComponentId`]s do not exist in the [`World`] or if the
/// entity has been despawned while this `EntityWorldMut` is still alive.
pub fn remove_by_ids(&mut self, component_ids: &[ComponentId]) -> &mut Self {
self.assert_not_despawned();
let components = &mut self.world.components;
let bundle_id = self
.world
.bundles
.init_dynamic_info(components, component_ids);
// SAFETY: the `BundleInfo` for this `bundle_id` is initialized above
unsafe { self.remove_bundle(bundle_id) };
self.world.flush();
self.update_location();
self
}
/// Removes all components associated with the entity.
///
/// # Panics
@ -2107,6 +2132,161 @@ impl<'w> EntityWorldMut<'w> {
self.update_location();
self
}
/// Clones parts of an entity (components, observers, etc.) onto another entity,
/// configured through [`EntityCloneBuilder`].
///
/// By default, the other entity will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// Configure through [`EntityCloneBuilder`] as follows:
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component, Clone, PartialEq, Debug)]
/// # struct ComponentA;
/// # #[derive(Component, Clone, PartialEq, Debug)]
/// # struct ComponentB;
/// # let mut world = World::new();
/// # let entity = world.spawn((ComponentA, ComponentB)).id();
/// # let target = world.spawn_empty().id();
/// world.entity_mut(entity).clone_with(target, |builder| {
/// builder.deny::<ComponentB>();
/// });
/// # assert_eq!(world.get::<ComponentA>(target), Some(&ComponentA));
/// # assert_eq!(world.get::<ComponentB>(target), None);
/// ```
///
/// See the following for more options:
/// - [`EntityCloneBuilder`]
/// - [`CloneEntityWithObserversExt`](crate::observer::CloneEntityWithObserversExt)
/// - `CloneEntityHierarchyExt`
///
/// # Panics
///
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
/// - If the target entity does not exist.
pub fn clone_with(
&mut self,
target: Entity,
config: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> &mut Self {
self.assert_not_despawned();
let mut builder = EntityCloneBuilder::new(self.world);
config(&mut builder);
builder.clone_entity(self.entity, target);
self.world.flush();
self.update_location();
self
}
/// Spawns a clone of this entity and returns the [`Entity`] of the clone.
///
/// The clone will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// To configure cloning behavior (such as only cloning certain components),
/// use [`EntityWorldMut::clone_and_spawn_with`].
///
/// # Panics
///
/// If this entity has been despawned while this `EntityWorldMut` is still alive.
pub fn clone_and_spawn(&mut self) -> Entity {
self.clone_and_spawn_with(|_| {})
}
/// Spawns a clone of this entity and allows configuring cloning behavior
/// using [`EntityCloneBuilder`], returning the [`Entity`] of the clone.
///
/// By default, the clone will receive all the components of the original that implement
/// [`Clone`] or [`Reflect`](bevy_reflect::Reflect).
///
/// Configure through [`EntityCloneBuilder`] as follows:
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component, Clone, PartialEq, Debug)]
/// # struct ComponentA;
/// # #[derive(Component, Clone, PartialEq, Debug)]
/// # struct ComponentB;
/// # let mut world = World::new();
/// # let entity = world.spawn((ComponentA, ComponentB)).id();
/// let entity_clone = world.entity_mut(entity).clone_and_spawn_with(|builder| {
/// builder.deny::<ComponentB>();
/// });
/// # assert_eq!(world.get::<ComponentA>(entity_clone), Some(&ComponentA));
/// # assert_eq!(world.get::<ComponentB>(entity_clone), None);
/// ```
///
/// See the following for more options:
/// - [`EntityCloneBuilder`]
/// - [`CloneEntityWithObserversExt`](crate::observer::CloneEntityWithObserversExt)
/// - `CloneEntityHierarchyExt`
///
/// # Panics
///
/// If this entity has been despawned while this `EntityWorldMut` is still alive.
pub fn clone_and_spawn_with(
&mut self,
config: impl FnOnce(&mut EntityCloneBuilder) + Send + Sync + 'static,
) -> Entity {
self.assert_not_despawned();
let entity_clone = self.world.entities.reserve_entity();
self.world.flush();
let mut builder = EntityCloneBuilder::new(self.world);
config(&mut builder);
builder.clone_entity(self.entity, entity_clone);
self.world.flush();
self.update_location();
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
///
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
/// - If the target entity does not exist.
pub fn clone_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.assert_not_despawned();
let mut builder = EntityCloneBuilder::new(self.world);
builder.deny_all().allow::<B>();
builder.clone_entity(self.entity, target);
self.world.flush();
self.update_location();
self
}
/// 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
///
/// - If this entity has been despawned while this `EntityWorldMut` is still alive.
/// - If the target entity does not exist.
pub fn move_components<B: Bundle>(&mut self, target: Entity) -> &mut Self {
self.assert_not_despawned();
let mut builder = EntityCloneBuilder::new(self.world);
builder.deny_all().allow::<B>();
builder.move_components(true);
builder.clone_entity(self.entity, target);
self.world.flush();
self.update_location();
self
}
}
/// # Safety
@ -4776,4 +4956,75 @@ mod tests {
world.flush();
assert_eq!(world.resource_mut::<TestVec>().0.as_slice(), &expected[..]);
}
#[test]
fn entity_world_mut_clone_and_move_components() {
#[derive(Component, Clone, PartialEq, Debug)]
struct A;
#[derive(Component, Clone, PartialEq, Debug)]
struct B;
#[derive(Component, Clone, PartialEq, Debug)]
struct C(u32);
#[derive(Component, Clone, PartialEq, Debug, Default)]
struct D;
let mut world = World::new();
let entity_a = world.spawn((A, B, C(5))).id();
let entity_b = world.spawn((A, C(4))).id();
world.entity_mut(entity_a).clone_components::<B>(entity_b);
assert_eq!(world.entity(entity_a).get::<B>(), Some(&B));
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B));
world.entity_mut(entity_a).move_components::<C>(entity_b);
assert_eq!(world.entity(entity_a).get::<C>(), None);
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(5)));
assert_eq!(world.entity(entity_a).get::<A>(), Some(&A));
assert_eq!(world.entity(entity_b).get::<A>(), Some(&A));
}
#[test]
fn entity_world_mut_clone_with_move_and_require() {
#[derive(Component, Clone, PartialEq, Debug)]
#[require(B)]
struct A;
#[derive(Component, Clone, PartialEq, Debug, Default)]
#[require(C(|| C(3)))]
struct B;
#[derive(Component, Clone, PartialEq, Debug, Default)]
#[require(D)]
struct C(u32);
#[derive(Component, Clone, PartialEq, Debug, Default)]
struct D;
let mut world = World::new();
let entity_a = world.spawn(A).id();
let entity_b = world.spawn_empty().id();
world.entity_mut(entity_a).clone_with(entity_b, |builder| {
builder.move_components(true);
builder.without_required_components(|builder| {
builder.deny::<A>();
});
});
assert_eq!(world.entity(entity_a).get::<A>(), Some(&A));
assert_eq!(world.entity(entity_b).get::<A>(), None);
assert_eq!(world.entity(entity_a).get::<B>(), None);
assert_eq!(world.entity(entity_b).get::<B>(), Some(&B));
assert_eq!(world.entity(entity_a).get::<C>(), None);
assert_eq!(world.entity(entity_b).get::<C>(), Some(&C(3)));
assert_eq!(world.entity(entity_a).get::<D>(), None);
assert_eq!(world.entity(entity_b).get::<D>(), Some(&D));
}
}