Skip to content

Commit 3caca42

Browse files
allow EntityCloner to move components without Clone or Reflect (#20065)
# Objective Fix #18079 ## Solution - `EntityCloner` can now move components that don't have `Clone` or `Reflect` implementation. - Components with `ComponentCloneBehavior::Ignore` will not be moved. - Components with `ComponentCloneBehavior::Custom` will be cloned using their defined `ComponentCloneFn` and then removed from the source entity to respect their `queue_deferred` logic. - Relationships still need to be `Clone` or `Reflect` to be movable. - Custom relationship data is now correctly preserved when cloned or moved using `EntityCloner`. ## Testing - Added new tests for moving components --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
1 parent 554bc7b commit 3caca42

File tree

8 files changed

+756
-47
lines changed

8 files changed

+756
-47
lines changed

crates/bevy_ecs/macros/src/component.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,14 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
293293
.then_some(quote! { #bevy_ecs_path::component::Immutable })
294294
.unwrap_or(quote! { #bevy_ecs_path::component::Mutable });
295295

296-
let clone_behavior = if relationship_target.is_some() {
297-
quote!(#bevy_ecs_path::component::ComponentCloneBehavior::Custom(#bevy_ecs_path::relationship::clone_relationship_target::<Self>))
296+
let clone_behavior = if relationship_target.is_some() || relationship.is_some() {
297+
quote!(
298+
use #bevy_ecs_path::relationship::{
299+
RelationshipCloneBehaviorBase, RelationshipCloneBehaviorViaClone, RelationshipCloneBehaviorViaReflect,
300+
RelationshipTargetCloneBehaviorViaClone, RelationshipTargetCloneBehaviorViaReflect, RelationshipTargetCloneBehaviorHierarchy
301+
};
302+
(&&&&&&&#bevy_ecs_path::relationship::RelationshipCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
303+
)
298304
} else if let Some(behavior) = attrs.clone_behavior {
299305
quote!(#bevy_ecs_path::component::ComponentCloneBehavior::#behavior)
300306
} else {

crates/bevy_ecs/src/bundle/remove.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub(crate) struct BundleRemover<'w> {
2222
old_and_new_table: Option<(NonNull<Table>, NonNull<Table>)>,
2323
old_archetype: NonNull<Archetype>,
2424
new_archetype: NonNull<Archetype>,
25+
pub(crate) relationship_hook_mode: RelationshipHookMode,
2526
}
2627

2728
impl<'w> BundleRemover<'w> {
@@ -97,6 +98,7 @@ impl<'w> BundleRemover<'w> {
9798
old_archetype: old_archetype.into(),
9899
old_and_new_table: tables,
99100
world: world.as_unsafe_world_cell(),
101+
relationship_hook_mode: RelationshipHookMode::Run,
100102
};
101103
if is_new_created {
102104
remover
@@ -160,7 +162,7 @@ impl<'w> BundleRemover<'w> {
160162
entity,
161163
bundle_components_in_archetype(),
162164
caller,
163-
RelationshipHookMode::Run,
165+
self.relationship_hook_mode,
164166
);
165167
if self.old_archetype.as_ref().has_remove_observer() {
166168
deferred_world.trigger_observers(

crates/bevy_ecs/src/component/clone.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ use core::marker::PhantomData;
33
use crate::component::Component;
44
use crate::entity::{ComponentCloneCtx, SourceComponent};
55

6-
/// Function type that can be used to clone an entity.
6+
/// Function type that can be used to clone a component of an entity.
77
pub type ComponentCloneFn = fn(&SourceComponent, &mut ComponentCloneCtx);
88

9-
/// The clone behavior to use when cloning a [`Component`].
9+
/// The clone behavior to use when cloning or moving a [`Component`].
1010
#[derive(Clone, Debug, Default, PartialEq, Eq)]
1111
pub enum ComponentCloneBehavior {
1212
/// Uses the default behavior (which is passed to [`ComponentCloneBehavior::resolve`])
1313
#[default]
1414
Default,
15-
/// Do not clone this component.
15+
/// Do not clone/move this component.
1616
Ignore,
1717
/// Uses a custom [`ComponentCloneFn`].
1818
Custom(ComponentCloneFn),

0 commit comments

Comments
 (0)