From e275156de551bcd7dfa5a6acdef43b3218906985 Mon Sep 17 00:00:00 2001 From: eugineerd Date: Wed, 9 Jul 2025 20:31:06 +0000 Subject: [PATCH] update component cloning documentation to mention moving components --- crates/bevy_ecs/src/component.rs | 6 +++--- crates/bevy_ecs/src/entity/clone_entities.rs | 20 ++++++++++++++++++- .../src/system/commands/entity_command.rs | 16 +++++++++++++-- crates/bevy_ecs/src/system/commands/mod.rs | 13 ++++++++---- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 615c5903f8..886f26b797 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -1035,16 +1035,16 @@ impl ComponentDescriptor { } } -/// Function type that can be used to clone an entity. +/// Function type that can be used to clone a component of an entity. pub type ComponentCloneFn = fn(&SourceComponent, &mut ComponentCloneCtx); -/// The clone behavior to use when cloning a [`Component`]. +/// The clone behavior to use when cloning or moving a [`Component`]. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub enum ComponentCloneBehavior { /// Uses the default behavior (which is passed to [`ComponentCloneBehavior::resolve`]) #[default] Default, - /// Do not clone this component. + /// Do not clone/move this component. Ignore, /// Uses a custom [`ComponentCloneFn`]. Custom(ComponentCloneFn), diff --git a/crates/bevy_ecs/src/entity/clone_entities.rs b/crates/bevy_ecs/src/entity/clone_entities.rs index 3811c1c71d..89f0a370b8 100644 --- a/crates/bevy_ecs/src/entity/clone_entities.rs +++ b/crates/bevy_ecs/src/entity/clone_entities.rs @@ -349,6 +349,19 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> { /// 2. component-defined handler using [`Component::clone_behavior`] /// 3. default handler override using [`EntityClonerBuilder::with_default_clone_fn`]. /// 4. reflect-based or noop default clone handler depending on if `bevy_reflect` feature is enabled or not. +/// +/// # Moving components +/// [`EntityCloner`] can be configured to move components instead of cloning them by using [`EntityClonerBuilder::move_components`]. +/// In this mode components will be moved - removed from source entity and added to the target entity. +/// +/// Components with [`ComponentCloneBehavior::Ignore`] clone behavior will not be moved, while components that +/// have a [`ComponentCloneBehavior::Custom`] clone behavior will be cloned using it and then removed from the source entity. +/// All other components will be bitwise copied from the source entity onto the target entity and then removed without dropping. +/// +/// Choosing to move components instead of cloning makes [`EntityClonerBuilder::with_default_clone_fn`] ineffective since it's replaced by +/// move handler for components that have [`ComponentCloneBehavior::Default`] clone behavior. +/// +/// Note that moving components still triggers `on_remove` hooks/observers on source entity and `on_insert`/`on_add` hooks/observers on the target entity. #[derive(Default)] pub struct EntityCloner { filter: EntityClonerFilter, @@ -400,6 +413,7 @@ impl<'a> BundleScratch<'a> { /// /// # Safety /// All [`ComponentId`] values in this instance must come from `world`. + #[track_caller] pub(crate) unsafe fn write( self, world: &mut World, @@ -709,7 +723,7 @@ impl EntityCloner { } } - (/* don't drop */ false, ()) + (/* should drop? */ false, ()) }, ); } @@ -776,6 +790,8 @@ impl<'w, Filter: CloneByFilter> EntityClonerBuilder<'w, Filter> { } /// Sets the default clone function to use. + /// + /// Will be overridden if [`EntityClonerBuilder::move_components`] is enabled. pub fn with_default_clone_fn(&mut self, clone_fn: ComponentCloneFn) -> &mut Self { self.state.default_clone_fn = clone_fn; self @@ -788,6 +804,8 @@ impl<'w, Filter: CloneByFilter> EntityClonerBuilder<'w, Filter> { /// /// The setting only applies to components that are allowed through the filter /// at the time [`EntityClonerBuilder::clone_entity`] is called. + /// + /// Enabling this overrides any custom function set with [`EntityClonerBuilder::with_default_clone_fn`]. pub fn move_components(&mut self, enable: bool) -> &mut Self { self.state.move_components = enable; self diff --git a/crates/bevy_ecs/src/system/commands/entity_command.rs b/crates/bevy_ecs/src/system/commands/entity_command.rs index 6d977e808d..74f206b348 100644 --- a/crates/bevy_ecs/src/system/commands/entity_command.rs +++ b/crates/bevy_ecs/src/system/commands/entity_command.rs @@ -310,8 +310,20 @@ pub fn clone_components(target: Entity) -> impl EntityCommand { } } -/// An [`EntityCommand`] that clones the specified components of an entity -/// and inserts them into another entity, then removes them from the original entity. +/// An [`EntityCommand`] moves the specified components of this entity into another entity. +/// +/// Components with [`Ignore`] clone behavior will not be moved, while components that +/// have a [`Custom`] clone behavior will be cloned using it and then removed from the source entity. +/// All other components will be moved without any other special handling. +/// +/// Note that this will trigger `on_remove` hooks/observers on this entity and `on_insert`/`on_add` hooks/observers on the target entity. +/// +/// # Panics +/// +/// The command will panic when applied if the target entity does not exist. +/// +/// [`Ignore`]: crate::component::ComponentCloneBehavior::Ignore +/// [`Custom`]: crate::component::ComponentCloneBehavior::Custom pub fn move_components(target: Entity) -> impl EntityCommand { move |mut entity: EntityWorldMut| { entity.move_components::(target); diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index a43dea5627..f7e1942379 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -2234,15 +2234,20 @@ impl<'a> EntityCommands<'a> { self.queue(entity_command::clone_components::(target)) } - /// Clones the specified components of this entity and inserts them into another entity, - /// then removes the components from this entity. + /// Moves the specified components of this entity into another entity. /// - /// Components can only be cloned if they implement - /// [`Clone`] or [`Reflect`](bevy_reflect::Reflect). + /// Components with [`Ignore`] clone behavior will not be moved, while components that + /// have a [`Custom`] clone behavior will be cloned using it and then removed from the source entity. + /// All other components will be moved without any other special handling. + /// + /// Note that this will trigger `on_remove` hooks/observers on this entity and `on_insert`/`on_add` hooks/observers on the target entity. /// /// # Panics /// /// The command will panic when applied if the target entity does not exist. + /// + /// [`Ignore`]: crate::component::ComponentCloneBehavior::Ignore + /// [`Custom`]: crate::component::ComponentCloneBehavior::Custom pub fn move_components(&mut self, target: Entity) -> &mut Self { self.queue(entity_command::move_components::(target)) }