Path: blob/main/crates/bevy_ecs/src/entity/clone_entities.rs
6849 views
use alloc::{boxed::Box, collections::VecDeque, vec::Vec};1use bevy_platform::collections::{hash_map::Entry, HashMap, HashSet};2use bevy_ptr::{Ptr, PtrMut};3use bevy_utils::prelude::DebugName;4use bumpalo::Bump;5use core::{any::TypeId, cell::LazyCell, ops::Range};6use derive_more::derive::From;78use crate::{9archetype::Archetype,10bundle::{Bundle, BundleRemover, InsertMode},11change_detection::MaybeLocation,12component::{Component, ComponentCloneBehavior, ComponentCloneFn, ComponentId, ComponentInfo},13entity::{hash_map::EntityHashMap, Entities, Entity, EntityMapper},14query::DebugCheckedUnwrap,15relationship::RelationshipHookMode,16world::World,17};1819/// Provides read access to the source component (the component being cloned) in a [`ComponentCloneFn`].20pub struct SourceComponent<'a> {21ptr: Ptr<'a>,22info: &'a ComponentInfo,23}2425impl<'a> SourceComponent<'a> {26/// Returns a reference to the component on the source entity.27///28/// Will return `None` if `ComponentId` of requested component does not match `ComponentId` of source component29pub fn read<C: Component>(&self) -> Option<&C> {30if self31.info32.type_id()33.is_some_and(|id| id == TypeId::of::<C>())34{35// SAFETY:36// - Components and ComponentId are from the same world37// - source_component_ptr holds valid data of the type referenced by ComponentId38unsafe { Some(self.ptr.deref::<C>()) }39} else {40None41}42}4344/// Returns the "raw" pointer to the source component.45pub fn ptr(&self) -> Ptr<'a> {46self.ptr47}4849/// Returns a reference to the component on the source entity as [`&dyn Reflect`](bevy_reflect::Reflect).50///51/// Will return `None` if:52/// - World does not have [`AppTypeRegistry`](`crate::reflect::AppTypeRegistry`).53/// - Component does not implement [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr).54/// - Component is not registered.55/// - Component does not have [`TypeId`]56/// - Registered [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr)'s [`TypeId`] does not match component's [`TypeId`]57#[cfg(feature = "bevy_reflect")]58pub fn read_reflect(59&self,60registry: &bevy_reflect::TypeRegistry,61) -> Option<&dyn bevy_reflect::Reflect> {62let type_id = self.info.type_id()?;63let reflect_from_ptr = registry.get_type_data::<bevy_reflect::ReflectFromPtr>(type_id)?;64if reflect_from_ptr.type_id() != type_id {65return None;66}67// SAFETY: `source_component_ptr` stores data represented by `component_id`, which we used to get `ReflectFromPtr`.68unsafe { Some(reflect_from_ptr.as_reflect(self.ptr)) }69}70}7172/// Context for component clone handlers.73///74/// Provides fast access to useful resources like [`AppTypeRegistry`](crate::reflect::AppTypeRegistry)75/// and allows component clone handler to get information about component being cloned.76pub struct ComponentCloneCtx<'a, 'b> {77component_id: ComponentId,78target_component_written: bool,79target_component_moved: bool,80bundle_scratch: &'a mut BundleScratch<'b>,81bundle_scratch_allocator: &'b Bump,82entities: &'a Entities,83source: Entity,84target: Entity,85component_info: &'a ComponentInfo,86state: &'a mut EntityClonerState,87mapper: &'a mut dyn EntityMapper,88#[cfg(feature = "bevy_reflect")]89type_registry: Option<&'a crate::reflect::AppTypeRegistry>,90#[cfg(not(feature = "bevy_reflect"))]91#[expect(dead_code, reason = "type_registry is only used with bevy_reflect")]92type_registry: Option<&'a ()>,93}9495impl<'a, 'b> ComponentCloneCtx<'a, 'b> {96/// Create a new instance of `ComponentCloneCtx` that can be passed to component clone handlers.97///98/// # Safety99/// Caller must ensure that:100/// - `component_info` corresponds to the `component_id` in the same world,.101/// - `source_component_ptr` points to a valid component of type represented by `component_id`.102unsafe fn new(103component_id: ComponentId,104source: Entity,105target: Entity,106bundle_scratch_allocator: &'b Bump,107bundle_scratch: &'a mut BundleScratch<'b>,108entities: &'a Entities,109component_info: &'a ComponentInfo,110entity_cloner: &'a mut EntityClonerState,111mapper: &'a mut dyn EntityMapper,112#[cfg(feature = "bevy_reflect")] type_registry: Option<&'a crate::reflect::AppTypeRegistry>,113#[cfg(not(feature = "bevy_reflect"))] type_registry: Option<&'a ()>,114) -> Self {115Self {116component_id,117source,118target,119bundle_scratch,120target_component_written: false,121target_component_moved: false,122bundle_scratch_allocator,123entities,124mapper,125component_info,126state: entity_cloner,127type_registry,128}129}130131/// Returns true if [`write_target_component`](`Self::write_target_component`) was called before.132pub fn target_component_written(&self) -> bool {133self.target_component_written134}135136/// Returns `true` if used in moving context137pub fn moving(&self) -> bool {138self.state.move_components139}140141/// Returns the current source entity.142pub fn source(&self) -> Entity {143self.source144}145146/// Returns the current target entity.147pub fn target(&self) -> Entity {148self.target149}150151/// Returns the [`ComponentId`] of the component being cloned.152pub fn component_id(&self) -> ComponentId {153self.component_id154}155156/// Returns the [`ComponentInfo`] of the component being cloned.157pub fn component_info(&self) -> &ComponentInfo {158self.component_info159}160161/// Returns true if the [`EntityCloner`] is configured to recursively clone entities. When this is enabled,162/// entities stored in a cloned entity's [`RelationshipTarget`](crate::relationship::RelationshipTarget) component with163/// [`RelationshipTarget::LINKED_SPAWN`](crate::relationship::RelationshipTarget::LINKED_SPAWN) will also be cloned.164#[inline]165pub fn linked_cloning(&self) -> bool {166self.state.linked_cloning167}168169/// Returns this context's [`EntityMapper`].170pub fn entity_mapper(&mut self) -> &mut dyn EntityMapper {171self.mapper172}173174/// Writes component data to target entity.175///176/// # Panics177/// This will panic if:178/// - Component has already been written once.179/// - Component being written is not registered in the world.180/// - `ComponentId` of component being written does not match expected `ComponentId`.181pub fn write_target_component<C: Component>(&mut self, mut component: C) {182C::map_entities(&mut component, &mut self.mapper);183let debug_name = DebugName::type_name::<C>();184let short_name = debug_name.shortname();185if self.target_component_written {186panic!("Trying to write component '{short_name}' multiple times")187}188if self189.component_info190.type_id()191.is_none_or(|id| id != TypeId::of::<C>())192{193panic!("TypeId of component '{short_name}' does not match source component TypeId")194};195// SAFETY: the TypeId of self.component_id has been checked to ensure it matches `C`196unsafe {197self.bundle_scratch198.push(self.bundle_scratch_allocator, self.component_id, component);199};200self.target_component_written = true;201}202203/// Writes component data to target entity by providing a pointer to source component data.204///205/// # Safety206/// Caller must ensure that the passed in `ptr` references data that corresponds to the type of the source / target [`ComponentId`].207/// `ptr` must also contain data that the written component can "own" (for example, this should not directly copy non-Copy data).208///209/// # Panics210/// This will panic if component has already been written once.211pub unsafe fn write_target_component_ptr(&mut self, ptr: Ptr) {212if self.target_component_written {213panic!("Trying to write component multiple times")214}215let layout = self.component_info.layout();216let target_ptr = self.bundle_scratch_allocator.alloc_layout(layout);217core::ptr::copy_nonoverlapping(ptr.as_ptr(), target_ptr.as_ptr(), layout.size());218self.bundle_scratch219.push_ptr(self.component_id, PtrMut::new(target_ptr));220self.target_component_written = true;221}222223/// Writes component data to target entity.224///225/// # Panics226/// This will panic if:227/// - World does not have [`AppTypeRegistry`](`crate::reflect::AppTypeRegistry`).228/// - Component does not implement [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr).229/// - Source component does not have [`TypeId`].230/// - Passed component's [`TypeId`] does not match source component [`TypeId`].231/// - Component has already been written once.232#[cfg(feature = "bevy_reflect")]233pub fn write_target_component_reflect(&mut self, component: Box<dyn bevy_reflect::Reflect>) {234if self.target_component_written {235panic!("Trying to write component multiple times")236}237let source_type_id = self238.component_info239.type_id()240.expect("Source component must have TypeId");241let component_type_id = component.type_id();242if source_type_id != component_type_id {243panic!("Passed component TypeId does not match source component TypeId")244}245let component_layout = self.component_info.layout();246247let component_data_ptr = Box::into_raw(component).cast::<u8>();248let target_component_data_ptr =249self.bundle_scratch_allocator.alloc_layout(component_layout);250// SAFETY:251// - target_component_data_ptr and component_data have the same data type.252// - component_data_ptr has layout of component_layout253unsafe {254core::ptr::copy_nonoverlapping(255component_data_ptr,256target_component_data_ptr.as_ptr(),257component_layout.size(),258);259self.bundle_scratch260.push_ptr(self.component_id, PtrMut::new(target_component_data_ptr));261262if component_layout.size() > 0 {263// Ensure we don't attempt to deallocate zero-sized components264alloc::alloc::dealloc(component_data_ptr, component_layout);265}266}267268self.target_component_written = true;269}270271/// Returns [`AppTypeRegistry`](`crate::reflect::AppTypeRegistry`) if it exists in the world.272///273/// NOTE: Prefer this method instead of manually reading the resource from the world.274#[cfg(feature = "bevy_reflect")]275pub fn type_registry(&self) -> Option<&crate::reflect::AppTypeRegistry> {276self.type_registry277}278279/// Queues the `entity` to be cloned by the current [`EntityCloner`]280pub fn queue_entity_clone(&mut self, entity: Entity) {281let target = self.entities.reserve_entity();282self.mapper.set_mapped(entity, target);283self.state.clone_queue.push_back(entity);284}285286/// Queues a deferred clone operation, which will run with exclusive [`World`] access immediately after calling the clone handler for each component on an entity.287/// This exists, despite its similarity to [`Commands`](crate::system::Commands), to provide access to the entity mapper in the current context.288pub fn queue_deferred(289&mut self,290deferred: impl FnOnce(&mut World, &mut dyn EntityMapper) + 'static,291) {292self.state.deferred_commands.push_back(Box::new(deferred));293}294295/// Marks component as moved and it's `drop` won't run.296fn move_component(&mut self) {297self.target_component_moved = true;298self.target_component_written = true;299}300}301302/// A configuration determining how to clone entities. This can be built using [`EntityCloner::build_opt_out`]/303/// [`opt_in`](EntityCloner::build_opt_in), which304/// returns an [`EntityClonerBuilder`].305///306/// After configuration is complete an entity can be cloned using [`Self::clone_entity`].307///308///```309/// use bevy_ecs::prelude::*;310/// use bevy_ecs::entity::EntityCloner;311///312/// #[derive(Component, Clone, PartialEq, Eq)]313/// struct A {314/// field: usize,315/// }316///317/// let mut world = World::default();318///319/// let component = A { field: 5 };320///321/// let entity = world.spawn(component.clone()).id();322/// let entity_clone = world.spawn_empty().id();323///324/// EntityCloner::build_opt_out(&mut world).clone_entity(entity, entity_clone);325///326/// assert!(world.get::<A>(entity_clone).is_some_and(|c| *c == component));327///```328///329/// # Default cloning strategy330/// By default, all types that derive [`Component`] and implement either [`Clone`] or `Reflect` (with `ReflectComponent`) will be cloned331/// (with `Clone`-based implementation preferred in case component implements both).332///333/// It should be noted that if `Component` is implemented manually or if `Clone` implementation is conditional334/// (like when deriving `Clone` for a type with a generic parameter without `Clone` bound),335/// the component will be cloned using the [default cloning strategy](crate::component::ComponentCloneBehavior::global_default_fn).336/// To use `Clone`-based handler ([`ComponentCloneBehavior::clone`]) in this case it should be set manually using one337/// of the methods mentioned in the [Clone Behaviors](#Clone-Behaviors) section338///339/// Here's an example of how to do it using [`clone_behavior`](Component::clone_behavior):340/// ```341/// # use bevy_ecs::prelude::*;342/// # use bevy_ecs::component::{StorageType, ComponentCloneBehavior, Mutable};343/// #[derive(Clone, Component)]344/// #[component(clone_behavior = clone::<Self>())]345/// struct SomeComponent;346///347/// ```348///349/// # Clone Behaviors350/// [`EntityCloner`] clones entities by cloning components using [`ComponentCloneBehavior`], and there are multiple layers351/// to decide which handler to use for which component. The overall hierarchy looks like this (priority from most to least):352/// 1. local overrides using [`EntityClonerBuilder::override_clone_behavior`]353/// 2. component-defined handler using [`Component::clone_behavior`]354/// 3. default handler override using [`EntityClonerBuilder::with_default_clone_fn`].355/// 4. reflect-based or noop default clone handler depending on if `bevy_reflect` feature is enabled or not.356///357/// # Moving components358/// [`EntityCloner`] can be configured to move components instead of cloning them by using [`EntityClonerBuilder::move_components`].359/// In this mode components will be moved - removed from source entity and added to the target entity.360///361/// Components with [`ComponentCloneBehavior::Ignore`] clone behavior will not be moved, while components that362/// have a [`ComponentCloneBehavior::Custom`] clone behavior will be cloned using it and then removed from the source entity.363/// All other components will be bitwise copied from the source entity onto the target entity and then removed without dropping.364///365/// Choosing to move components instead of cloning makes [`EntityClonerBuilder::with_default_clone_fn`] ineffective since it's replaced by366/// move handler for components that have [`ComponentCloneBehavior::Default`] clone behavior.367///368/// Note that moving components still triggers `on_remove` hooks/observers on source entity and `on_insert`/`on_add` hooks/observers on the target entity.369#[derive(Default)]370pub struct EntityCloner {371filter: EntityClonerFilter,372state: EntityClonerState,373}374375/// An expandable scratch space for defining a dynamic bundle.376struct BundleScratch<'a> {377component_ids: Vec<ComponentId>,378component_ptrs: Vec<PtrMut<'a>>,379}380381impl<'a> BundleScratch<'a> {382pub(crate) fn with_capacity(capacity: usize) -> Self {383Self {384component_ids: Vec::with_capacity(capacity),385component_ptrs: Vec::with_capacity(capacity),386}387}388389/// Pushes the `ptr` component onto this storage with the given `id` [`ComponentId`].390///391/// # Safety392/// The `id` [`ComponentId`] must match the component `ptr` for whatever [`World`] this scratch will393/// be written to. `ptr` must contain valid uniquely-owned data that matches the type of component referenced394/// in `id`.395pub(crate) unsafe fn push_ptr(&mut self, id: ComponentId, ptr: PtrMut<'a>) {396self.component_ids.push(id);397self.component_ptrs.push(ptr);398}399400/// Pushes the `C` component onto this storage with the given `id` [`ComponentId`], using the given `bump` allocator.401///402/// # Safety403/// The `id` [`ComponentId`] must match the component `C` for whatever [`World`] this scratch will404/// be written to.405pub(crate) unsafe fn push<C: Component>(406&mut self,407allocator: &'a Bump,408id: ComponentId,409component: C,410) {411let component_ref = allocator.alloc(component);412self.component_ids.push(id);413self.component_ptrs.push(PtrMut::from(component_ref));414}415416/// Writes the scratch components to the given entity in the given world.417///418/// # Safety419/// All [`ComponentId`] values in this instance must come from `world`.420#[track_caller]421pub(crate) unsafe fn write(422self,423world: &mut World,424entity: Entity,425relationship_hook_insert_mode: RelationshipHookMode,426) {427// SAFETY:428// - All `component_ids` are from the same world as `entity`429// - All `component_data_ptrs` are valid types represented by `component_ids`430unsafe {431world.entity_mut(entity).insert_by_ids_internal(432&self.component_ids,433self.component_ptrs.into_iter().map(|ptr| ptr.promote()),434relationship_hook_insert_mode,435);436}437}438}439440impl EntityCloner {441/// Returns a new [`EntityClonerBuilder`] using the given `world` with the [`OptOut`] configuration.442///443/// This builder tries to clone every component from the source entity except for components that were444/// explicitly denied, for example by using the [`deny`](EntityClonerBuilder<OptOut>::deny) method.445///446/// Required components are not considered by denied components and must be explicitly denied as well if desired.447pub fn build_opt_out(world: &mut World) -> EntityClonerBuilder<'_, OptOut> {448EntityClonerBuilder {449world,450filter: Default::default(),451state: Default::default(),452}453}454455/// Returns a new [`EntityClonerBuilder`] using the given `world` with the [`OptIn`] configuration.456///457/// This builder tries to clone every component that was explicitly allowed from the source entity,458/// for example by using the [`allow`](EntityClonerBuilder<OptIn>::allow) method.459///460/// Components allowed to be cloned through this builder would also allow their required components,461/// which will be cloned from the source entity only if the target entity does not contain them already.462/// To skip adding required components see [`without_required_components`](EntityClonerBuilder<OptIn>::without_required_components).463pub fn build_opt_in(world: &mut World) -> EntityClonerBuilder<'_, OptIn> {464EntityClonerBuilder {465world,466filter: Default::default(),467state: Default::default(),468}469}470471/// Returns `true` if this cloner is configured to clone entities referenced in cloned components via [`RelationshipTarget::LINKED_SPAWN`](crate::relationship::RelationshipTarget::LINKED_SPAWN).472/// This will produce "deep" / recursive clones of relationship trees that have "linked spawn".473#[inline]474pub fn linked_cloning(&self) -> bool {475self.state.linked_cloning476}477478/// Clones and inserts components from the `source` entity into `target` entity using the stored configuration.479/// If this [`EntityCloner`] has [`EntityCloner::linked_cloning`], then it will recursively spawn entities as defined480/// by [`RelationshipTarget`](crate::relationship::RelationshipTarget) components with481/// [`RelationshipTarget::LINKED_SPAWN`](crate::relationship::RelationshipTarget::LINKED_SPAWN)482#[track_caller]483pub fn clone_entity(&mut self, world: &mut World, source: Entity, target: Entity) {484let mut map = EntityHashMap::<Entity>::new();485map.set_mapped(source, target);486self.clone_entity_mapped(world, source, &mut map);487}488489/// Clones and inserts components from the `source` entity into a newly spawned entity using the stored configuration.490/// If this [`EntityCloner`] has [`EntityCloner::linked_cloning`], then it will recursively spawn entities as defined491/// by [`RelationshipTarget`](crate::relationship::RelationshipTarget) components with492/// [`RelationshipTarget::LINKED_SPAWN`](crate::relationship::RelationshipTarget::LINKED_SPAWN)493#[track_caller]494pub fn spawn_clone(&mut self, world: &mut World, source: Entity) -> Entity {495let target = world.spawn_empty().id();496self.clone_entity(world, source, target);497target498}499500/// Clones the entity into whatever entity `mapper` chooses for it.501#[track_caller]502pub fn clone_entity_mapped(503&mut self,504world: &mut World,505source: Entity,506mapper: &mut dyn EntityMapper,507) -> Entity {508Self::clone_entity_mapped_internal(&mut self.state, &mut self.filter, world, source, mapper)509}510511#[track_caller]512#[inline]513fn clone_entity_mapped_internal(514state: &mut EntityClonerState,515filter: &mut impl CloneByFilter,516world: &mut World,517source: Entity,518mapper: &mut dyn EntityMapper,519) -> Entity {520// All relationships on the root should have their hooks run521let target = Self::clone_entity_internal(522state,523filter,524world,525source,526mapper,527RelationshipHookMode::Run,528);529let child_hook_insert_mode = if state.linked_cloning {530// When spawning "linked relationships", we want to ignore hooks for relationships we are spawning, while531// still registering with original relationship targets that are "not linked" to the current recursive spawn.532RelationshipHookMode::RunIfNotLinked533} else {534// If we are not cloning "linked relationships" recursively, then we want any cloned relationship components to535// register themselves with their original relationship target.536RelationshipHookMode::Run537};538loop {539let queued = state.clone_queue.pop_front();540if let Some(queued) = queued {541Self::clone_entity_internal(542state,543filter,544world,545queued,546mapper,547child_hook_insert_mode,548);549} else {550break;551}552}553target554}555556/// Clones and inserts components from the `source` entity into the entity mapped by `mapper` from `source` using the stored configuration.557#[track_caller]558fn clone_entity_internal(559state: &mut EntityClonerState,560filter: &mut impl CloneByFilter,561world: &mut World,562source: Entity,563mapper: &mut dyn EntityMapper,564relationship_hook_insert_mode: RelationshipHookMode,565) -> Entity {566let target = mapper.get_mapped(source);567// PERF: reusing allocated space across clones would be more efficient. Consider an allocation model similar to `Commands`.568let bundle_scratch_allocator = Bump::new();569let mut bundle_scratch: BundleScratch;570let mut moved_components: Vec<ComponentId> = Vec::new();571let mut deferred_cloned_component_ids: Vec<ComponentId> = Vec::new();572{573let world = world.as_unsafe_world_cell();574let source_entity = world.get_entity(source).expect("Source entity must exist");575576#[cfg(feature = "bevy_reflect")]577// SAFETY: we have unique access to `world`, nothing else accesses the registry at this moment, and we clone578// the registry, which prevents future conflicts.579let app_registry = unsafe {580world581.get_resource::<crate::reflect::AppTypeRegistry>()582.cloned()583};584#[cfg(not(feature = "bevy_reflect"))]585let app_registry = Option::<()>::None;586587let source_archetype = source_entity.archetype();588bundle_scratch = BundleScratch::with_capacity(source_archetype.component_count());589590let target_archetype = LazyCell::new(|| {591world592.get_entity(target)593.expect("Target entity must exist")594.archetype()595});596597if state.move_components {598moved_components.reserve(source_archetype.component_count());599// Replace default handler with special handler which would track if component was moved instead of cloned.600// This is later used to determine whether we need to run component's drop function when removing it from the source entity or not.601state.default_clone_fn = |_, ctx| ctx.move_component();602}603604filter.clone_components(source_archetype, target_archetype, |component| {605let handler = match state.clone_behavior_overrides.get(&component).or_else(|| {606world607.components()608.get_info(component)609.map(ComponentInfo::clone_behavior)610}) {611Some(behavior) => match behavior {612ComponentCloneBehavior::Default => state.default_clone_fn,613ComponentCloneBehavior::Ignore => return,614ComponentCloneBehavior::Custom(custom) => *custom,615},616None => state.default_clone_fn,617};618619// SAFETY: This component exists because it is present on the archetype.620let info = unsafe { world.components().get_info_unchecked(component) };621622// SAFETY:623// - There are no other mutable references to source entity.624// - `component` is from `source_entity`'s archetype625let source_component_ptr =626unsafe { source_entity.get_by_id(component).debug_checked_unwrap() };627628let source_component = SourceComponent {629info,630ptr: source_component_ptr,631};632633// SAFETY:634// - `components` and `component` are from the same world635// - `source_component_ptr` is valid and points to the same type as represented by `component`636let mut ctx = unsafe {637ComponentCloneCtx::new(638component,639source,640target,641&bundle_scratch_allocator,642&mut bundle_scratch,643world.entities(),644info,645state,646mapper,647app_registry.as_ref(),648)649};650651(handler)(&source_component, &mut ctx);652653if ctx.state.move_components {654if ctx.target_component_moved {655moved_components.push(component);656}657// Component wasn't written by the clone handler, so assume it's going to be658// cloned/processed using deferred_commands instead.659// This means that it's ComponentId won't be present in BundleScratch's component_ids,660// but it should still be removed when move_components is true.661else if !ctx.target_component_written() {662deferred_cloned_component_ids.push(component);663}664}665});666}667668world.flush();669670for deferred in state.deferred_commands.drain(..) {671(deferred)(world, mapper);672}673674if !world.entities.contains(target) {675panic!("Target entity does not exist");676}677678if state.move_components {679let mut source_entity = world.entity_mut(source);680681let cloned_components = if deferred_cloned_component_ids.is_empty() {682&bundle_scratch.component_ids683} else {684// Remove all cloned components with drop by concatenating both vectors685deferred_cloned_component_ids.extend(&bundle_scratch.component_ids);686&deferred_cloned_component_ids687};688source_entity.remove_by_ids_with_caller(689cloned_components,690MaybeLocation::caller(),691RelationshipHookMode::RunIfNotLinked,692BundleRemover::empty_pre_remove,693);694695let table_row = source_entity.location().table_row;696697// Copy moved components and then forget them without calling drop698source_entity.remove_by_ids_with_caller(699&moved_components,700MaybeLocation::caller(),701RelationshipHookMode::RunIfNotLinked,702|sparse_sets, mut table, components, bundle| {703for &component_id in bundle {704let Some(component_ptr) = sparse_sets705.get(component_id)706.and_then(|component| component.get(source))707.or_else(|| {708// SAFETY: table_row is within this table because we just got it from entity's current location709table.as_mut().and_then(|table| unsafe {710table.get_component(component_id, table_row)711})712})713else {714// Component was removed by some other component's clone side effect before we got to it.715continue;716};717718// SAFETY: component_id is valid because remove_by_ids_with_caller checked it before calling this closure719let info = unsafe { components.get_info_unchecked(component_id) };720let layout = info.layout();721let target_ptr = bundle_scratch_allocator.alloc_layout(layout);722// SAFETY:723// - component_ptr points to data with component layout724// - target_ptr was just allocated with component layout725// - component_ptr and target_ptr don't overlap726// - component_ptr matches component_id727unsafe {728core::ptr::copy_nonoverlapping(729component_ptr.as_ptr(),730target_ptr.as_ptr(),731layout.size(),732);733bundle_scratch.push_ptr(component_id, PtrMut::new(target_ptr));734}735}736737(/* should drop? */ false, ())738},739);740}741742// SAFETY:743// - All `component_ids` are from the same world as `target` entity744// - All `component_data_ptrs` are valid types represented by `component_ids`745unsafe { bundle_scratch.write(world, target, relationship_hook_insert_mode) };746target747}748}749750/// Part of the [`EntityCloner`], see there for more information.751struct EntityClonerState {752clone_behavior_overrides: HashMap<ComponentId, ComponentCloneBehavior>,753move_components: bool,754linked_cloning: bool,755default_clone_fn: ComponentCloneFn,756clone_queue: VecDeque<Entity>,757deferred_commands: VecDeque<Box<dyn FnOnce(&mut World, &mut dyn EntityMapper)>>,758}759760impl Default for EntityClonerState {761fn default() -> Self {762Self {763move_components: false,764linked_cloning: false,765default_clone_fn: ComponentCloneBehavior::global_default_fn(),766clone_behavior_overrides: Default::default(),767clone_queue: Default::default(),768deferred_commands: Default::default(),769}770}771}772773/// A builder for configuring [`EntityCloner`]. See [`EntityCloner`] for more information.774pub struct EntityClonerBuilder<'w, Filter> {775world: &'w mut World,776filter: Filter,777state: EntityClonerState,778}779780impl<'w, Filter: CloneByFilter> EntityClonerBuilder<'w, Filter> {781/// Internally calls [`EntityCloner::clone_entity`] on the builder's [`World`].782pub fn clone_entity(&mut self, source: Entity, target: Entity) -> &mut Self {783let mut mapper = EntityHashMap::<Entity>::new();784mapper.set_mapped(source, target);785EntityCloner::clone_entity_mapped_internal(786&mut self.state,787&mut self.filter,788self.world,789source,790&mut mapper,791);792self793}794795/// Finishes configuring [`EntityCloner`] returns it.796pub fn finish(self) -> EntityCloner {797EntityCloner {798filter: self.filter.into(),799state: self.state,800}801}802803/// Sets the default clone function to use.804///805/// Will be overridden if [`EntityClonerBuilder::move_components`] is enabled.806pub fn with_default_clone_fn(&mut self, clone_fn: ComponentCloneFn) -> &mut Self {807self.state.default_clone_fn = clone_fn;808self809}810811/// Sets whether the cloner should remove any components that were cloned,812/// effectively moving them from the source entity to the target.813///814/// This is disabled by default.815///816/// The setting only applies to components that are allowed through the filter817/// at the time [`EntityClonerBuilder::clone_entity`] is called.818///819/// Enabling this overrides any custom function set with [`EntityClonerBuilder::with_default_clone_fn`].820pub fn move_components(&mut self, enable: bool) -> &mut Self {821self.state.move_components = enable;822self823}824825/// Overrides the [`ComponentCloneBehavior`] for a component in this builder.826/// This handler will be used to clone the component instead of the global one defined by the [`EntityCloner`].827///828/// See [Handlers section of `EntityClonerBuilder`](EntityClonerBuilder#handlers) to understand how this affects handler priority.829pub fn override_clone_behavior<T: Component>(830&mut self,831clone_behavior: ComponentCloneBehavior,832) -> &mut Self {833if let Some(id) = self.world.components().valid_component_id::<T>() {834self.state835.clone_behavior_overrides836.insert(id, clone_behavior);837}838self839}840841/// Overrides the [`ComponentCloneBehavior`] for a component with the given `component_id` in this builder.842/// This handler will be used to clone the component instead of the global one defined by the [`EntityCloner`].843///844/// See [Handlers section of `EntityClonerBuilder`](EntityClonerBuilder#handlers) to understand how this affects handler priority.845pub fn override_clone_behavior_with_id(846&mut self,847component_id: ComponentId,848clone_behavior: ComponentCloneBehavior,849) -> &mut Self {850self.state851.clone_behavior_overrides852.insert(component_id, clone_behavior);853self854}855856/// Removes a previously set override of [`ComponentCloneBehavior`] for a component in this builder.857pub fn remove_clone_behavior_override<T: Component>(&mut self) -> &mut Self {858if let Some(id) = self.world.components().valid_component_id::<T>() {859self.state.clone_behavior_overrides.remove(&id);860}861self862}863864/// Removes a previously set override of [`ComponentCloneBehavior`] for a given `component_id` in this builder.865pub fn remove_clone_behavior_override_with_id(866&mut self,867component_id: ComponentId,868) -> &mut Self {869self.state.clone_behavior_overrides.remove(&component_id);870self871}872873/// When true this cloner will be configured to clone entities referenced in cloned components via [`RelationshipTarget::LINKED_SPAWN`](crate::relationship::RelationshipTarget::LINKED_SPAWN).874/// This will produce "deep" / recursive clones of relationship trees that have "linked spawn".875pub fn linked_cloning(&mut self, linked_cloning: bool) -> &mut Self {876self.state.linked_cloning = linked_cloning;877self878}879}880881impl<'w> EntityClonerBuilder<'w, OptOut> {882/// By default, any components denied through the filter will automatically883/// deny all of components they are required by too.884///885/// This method allows for a scoped mode where any changes to the filter886/// will not involve these requiring components.887///888/// If component `A` is denied in the `builder` closure here and component `B`889/// requires `A`, then `A` will be inserted with the value defined in `B`'s890/// [`Component` derive](https://docs.rs/bevy/latest/bevy/ecs/component/trait.Component.html#required-components).891/// This assumes `A` is missing yet at the target entity.892pub fn without_required_by_components(&mut self, builder: impl FnOnce(&mut Self)) -> &mut Self {893self.filter.attach_required_by_components = false;894builder(self);895self.filter.attach_required_by_components = true;896self897}898899/// Sets whether components are always cloned ([`InsertMode::Replace`], the default) or only if it is missing900/// ([`InsertMode::Keep`]) at the target entity.901///902/// This makes no difference if the target is spawned by the cloner.903pub fn insert_mode(&mut self, insert_mode: InsertMode) -> &mut Self {904self.filter.insert_mode = insert_mode;905self906}907908/// Disallows all components of the bundle from being cloned.909///910/// If component `A` is denied here and component `B` requires `A`, then `A`911/// is denied as well. See [`Self::without_required_by_components`] to alter912/// this behavior.913pub fn deny<T: Bundle>(&mut self) -> &mut Self {914let bundle_id = self.world.register_bundle::<T>().id();915self.deny_by_ids(bundle_id)916}917918/// Extends the list of components that shouldn't be cloned.919/// Supports filtering by [`TypeId`], [`ComponentId`], [`BundleId`](`crate::bundle::BundleId`), and [`IntoIterator`] yielding one of these.920///921/// If component `A` is denied here and component `B` requires `A`, then `A`922/// is denied as well. See [`Self::without_required_by_components`] to alter923/// this behavior.924pub fn deny_by_ids<M: Marker>(&mut self, ids: impl FilterableIds<M>) -> &mut Self {925ids.filter_ids(&mut |ids| match ids {926FilterableId::Type(type_id) => {927if let Some(id) = self.world.components().get_valid_id(type_id) {928self.filter.filter_deny(id, self.world);929}930}931FilterableId::Component(component_id) => {932self.filter.filter_deny(component_id, self.world);933}934FilterableId::Bundle(bundle_id) => {935if let Some(bundle) = self.world.bundles().get(bundle_id) {936let ids = bundle.explicit_components().iter();937for &id in ids {938self.filter.filter_deny(id, self.world);939}940}941}942});943self944}945}946947impl<'w> EntityClonerBuilder<'w, OptIn> {948/// By default, any components allowed through the filter will automatically949/// allow all of their required components.950///951/// This method allows for a scoped mode where any changes to the filter952/// will not involve required components.953///954/// If component `A` is allowed in the `builder` closure here and requires955/// component `B`, then `B` will be inserted with the value defined in `A`'s956/// [`Component` derive](https://docs.rs/bevy/latest/bevy/ecs/component/trait.Component.html#required-components).957/// This assumes `B` is missing yet at the target entity.958pub fn without_required_components(&mut self, builder: impl FnOnce(&mut Self)) -> &mut Self {959self.filter.attach_required_components = false;960builder(self);961self.filter.attach_required_components = true;962self963}964965/// Adds all components of the bundle to the list of components to clone.966///967/// If component `A` is allowed here and requires component `B`, then `B`968/// is allowed as well. See [`Self::without_required_components`]969/// to alter this behavior.970pub fn allow<T: Bundle>(&mut self) -> &mut Self {971let bundle_id = self.world.register_bundle::<T>().id();972self.allow_by_ids(bundle_id)973}974975/// Adds all components of the bundle to the list of components to clone if976/// the target does not contain them.977///978/// If component `A` is allowed here and requires component `B`, then `B`979/// is allowed as well. See [`Self::without_required_components`]980/// to alter this behavior.981pub fn allow_if_new<T: Bundle>(&mut self) -> &mut Self {982let bundle_id = self.world.register_bundle::<T>().id();983self.allow_by_ids_if_new(bundle_id)984}985986/// Extends the list of components to clone.987/// Supports filtering by [`TypeId`], [`ComponentId`], [`BundleId`](`crate::bundle::BundleId`), and [`IntoIterator`] yielding one of these.988///989/// If component `A` is allowed here and requires component `B`, then `B`990/// is allowed as well. See [`Self::without_required_components`]991/// to alter this behavior.992pub fn allow_by_ids<M: Marker>(&mut self, ids: impl FilterableIds<M>) -> &mut Self {993self.allow_by_ids_inner(ids, InsertMode::Replace);994self995}996997/// Extends the list of components to clone if the target does not contain them.998/// Supports filtering by [`TypeId`], [`ComponentId`], [`BundleId`](`crate::bundle::BundleId`), and [`IntoIterator`] yielding one of these.999///1000/// If component `A` is allowed here and requires component `B`, then `B`1001/// is allowed as well. See [`Self::without_required_components`]1002/// to alter this behavior.1003pub fn allow_by_ids_if_new<M: Marker>(&mut self, ids: impl FilterableIds<M>) -> &mut Self {1004self.allow_by_ids_inner(ids, InsertMode::Keep);1005self1006}10071008fn allow_by_ids_inner<M: Marker>(1009&mut self,1010ids: impl FilterableIds<M>,1011insert_mode: InsertMode,1012) {1013ids.filter_ids(&mut |id| match id {1014FilterableId::Type(type_id) => {1015if let Some(id) = self.world.components().get_valid_id(type_id) {1016self.filter.filter_allow(id, self.world, insert_mode);1017}1018}1019FilterableId::Component(component_id) => {1020self.filter1021.filter_allow(component_id, self.world, insert_mode);1022}1023FilterableId::Bundle(bundle_id) => {1024if let Some(bundle) = self.world.bundles().get(bundle_id) {1025let ids = bundle.explicit_components().iter();1026for &id in ids {1027self.filter.filter_allow(id, self.world, insert_mode);1028}1029}1030}1031});1032}1033}10341035/// Filters that can selectively clone components depending on its inner configuration are unified with this trait.1036#[doc(hidden)]1037pub trait CloneByFilter: Into<EntityClonerFilter> {1038/// The filter will call `clone_component` for every [`ComponentId`] that passes it.1039fn clone_components<'a>(1040&mut self,1041source_archetype: &Archetype,1042target_archetype: LazyCell<&'a Archetype, impl FnOnce() -> &'a Archetype>,1043clone_component: impl FnMut(ComponentId),1044);1045}10461047/// Part of the [`EntityCloner`], see there for more information.1048#[doc(hidden)]1049#[derive(From)]1050pub enum EntityClonerFilter {1051OptOut(OptOut),1052OptIn(OptIn),1053}10541055impl Default for EntityClonerFilter {1056fn default() -> Self {1057Self::OptOut(Default::default())1058}1059}10601061impl CloneByFilter for EntityClonerFilter {1062#[inline]1063fn clone_components<'a>(1064&mut self,1065source_archetype: &Archetype,1066target_archetype: LazyCell<&'a Archetype, impl FnOnce() -> &'a Archetype>,1067clone_component: impl FnMut(ComponentId),1068) {1069match self {1070Self::OptOut(filter) => {1071filter.clone_components(source_archetype, target_archetype, clone_component);1072}1073Self::OptIn(filter) => {1074filter.clone_components(source_archetype, target_archetype, clone_component);1075}1076}1077}1078}10791080/// Generic for [`EntityClonerBuilder`] that makes the cloner try to clone every component from the source entity1081/// except for components that were explicitly denied, for example by using the1082/// [`deny`](EntityClonerBuilder::deny) method.1083///1084/// Required components are not considered by denied components and must be explicitly denied as well if desired.1085pub struct OptOut {1086/// Contains the components that should not be cloned.1087deny: HashSet<ComponentId>,10881089/// Determines if a component is inserted when it is existing already.1090insert_mode: InsertMode,10911092/// Is `true` unless during [`EntityClonerBuilder::without_required_by_components`] which will suppress1093/// components that require denied components to be denied as well, causing them to be created independent1094/// from the value at the source entity if needed.1095attach_required_by_components: bool,1096}10971098impl Default for OptOut {1099fn default() -> Self {1100Self {1101deny: Default::default(),1102insert_mode: InsertMode::Replace,1103attach_required_by_components: true,1104}1105}1106}11071108impl CloneByFilter for OptOut {1109#[inline]1110fn clone_components<'a>(1111&mut self,1112source_archetype: &Archetype,1113target_archetype: LazyCell<&'a Archetype, impl FnOnce() -> &'a Archetype>,1114mut clone_component: impl FnMut(ComponentId),1115) {1116match self.insert_mode {1117InsertMode::Replace => {1118for component in source_archetype.iter_components() {1119if !self.deny.contains(&component) {1120clone_component(component);1121}1122}1123}1124InsertMode::Keep => {1125for component in source_archetype.iter_components() {1126if !target_archetype.contains(component) && !self.deny.contains(&component) {1127clone_component(component);1128}1129}1130}1131}1132}1133}11341135impl OptOut {1136/// Denies a component through the filter, also deny components that require `id` if1137/// [`Self::attach_required_by_components`] is true.1138#[inline]1139fn filter_deny(&mut self, id: ComponentId, world: &World) {1140self.deny.insert(id);1141if self.attach_required_by_components {1142if let Some(required_by) = world.components().get_required_by(id) {1143self.deny.extend(required_by.iter());1144};1145}1146}1147}11481149/// Generic for [`EntityClonerBuilder`] that makes the cloner try to clone every component that was explicitly1150/// allowed from the source entity, for example by using the [`allow`](EntityClonerBuilder::allow) method.1151///1152/// Required components are also cloned when the target entity does not contain them.1153pub struct OptIn {1154/// Contains the components explicitly allowed to be cloned.1155allow: HashMap<ComponentId, Explicit>,11561157/// Lists of required components, [`Explicit`] refers to a range in it.1158required_of_allow: Vec<ComponentId>,11591160/// Contains the components required by those in [`Self::allow`].1161/// Also contains the number of components in [`Self::allow`] each is required by to track1162/// when to skip cloning a required component after skipping explicit components that require it.1163required: HashMap<ComponentId, Required>,11641165/// Is `true` unless during [`EntityClonerBuilder::without_required_components`] which will suppress1166/// evaluating required components to clone, causing them to be created independent from the value at1167/// the source entity if needed.1168attach_required_components: bool,1169}11701171impl Default for OptIn {1172fn default() -> Self {1173Self {1174allow: Default::default(),1175required_of_allow: Default::default(),1176required: Default::default(),1177attach_required_components: true,1178}1179}1180}11811182impl CloneByFilter for OptIn {1183#[inline]1184fn clone_components<'a>(1185&mut self,1186source_archetype: &Archetype,1187target_archetype: LazyCell<&'a Archetype, impl FnOnce() -> &'a Archetype>,1188mut clone_component: impl FnMut(ComponentId),1189) {1190// track the amount of components left not being cloned yet to exit this method early1191let mut uncloned_components = source_archetype.component_count();11921193// track if any `Required::required_by_reduced` has been reduced so they are reset1194let mut reduced_any = false;11951196// clone explicit components1197for (&component, explicit) in self.allow.iter() {1198if uncloned_components == 0 {1199// exhausted all source components, reset changed `Required::required_by_reduced`1200if reduced_any {1201self.required1202.iter_mut()1203.for_each(|(_, required)| required.reset());1204}1205return;1206}12071208let do_clone = source_archetype.contains(component)1209&& (explicit.insert_mode == InsertMode::Replace1210|| !target_archetype.contains(component));1211if do_clone {1212clone_component(component);1213uncloned_components -= 1;1214} else if let Some(range) = explicit.required_range.clone() {1215for component in self.required_of_allow[range].iter() {1216// may be None if required component was also added as explicit later1217if let Some(required) = self.required.get_mut(component) {1218required.required_by_reduced -= 1;1219reduced_any = true;1220}1221}1222}1223}12241225let mut required_iter = self.required.iter_mut();12261227// clone required components1228let required_components = required_iter1229.by_ref()1230.filter_map(|(&component, required)| {1231let do_clone = required.required_by_reduced > 0 // required by a cloned component1232&& source_archetype.contains(component) // must exist to clone, may miss if removed1233&& !target_archetype.contains(component); // do not overwrite existing values12341235// reset changed `Required::required_by_reduced` as this is done being checked here1236required.reset();12371238do_clone.then_some(component)1239})1240.take(uncloned_components);12411242for required_component in required_components {1243clone_component(required_component);1244}12451246// if the `required_components` iterator has not been exhausted yet because the source has no more1247// components to clone, iterate the rest to reset changed `Required::required_by_reduced` for the1248// next clone1249if reduced_any {1250required_iter.for_each(|(_, required)| required.reset());1251}1252}1253}12541255impl OptIn {1256/// Allows a component through the filter, also allow required components if1257/// [`Self::attach_required_components`] is true.1258#[inline]1259fn filter_allow(&mut self, id: ComponentId, world: &World, mut insert_mode: InsertMode) {1260match self.allow.entry(id) {1261Entry::Vacant(explicit) => {1262// explicit components should not appear in the required map1263self.required.remove(&id);12641265if !self.attach_required_components {1266explicit.insert(Explicit {1267insert_mode,1268required_range: None,1269});1270} else {1271self.filter_allow_with_required(id, world, insert_mode);1272}1273}1274Entry::Occupied(mut explicit) => {1275let explicit = explicit.get_mut();12761277// set required component range if it was inserted with `None` earlier1278if self.attach_required_components && explicit.required_range.is_none() {1279if explicit.insert_mode == InsertMode::Replace {1280// do not overwrite with Keep if component was allowed as Replace earlier1281insert_mode = InsertMode::Replace;1282}12831284self.filter_allow_with_required(id, world, insert_mode);1285} else if explicit.insert_mode == InsertMode::Keep {1286// potentially overwrite Keep with Replace1287explicit.insert_mode = insert_mode;1288}1289}1290};1291}12921293// Allow a component through the filter and include required components.1294#[inline]1295fn filter_allow_with_required(1296&mut self,1297id: ComponentId,1298world: &World,1299insert_mode: InsertMode,1300) {1301let Some(info) = world.components().get_info(id) else {1302return;1303};13041305let iter = info1306.required_components()1307.iter_ids()1308.filter(|id| !self.allow.contains_key(id))1309.inspect(|id| {1310// set or increase the number of components this `id` is required by1311self.required1312.entry(*id)1313.and_modify(|required| {1314required.required_by += 1;1315required.required_by_reduced += 1;1316})1317.or_insert(Required {1318required_by: 1,1319required_by_reduced: 1,1320});1321});13221323let start = self.required_of_allow.len();1324self.required_of_allow.extend(iter);1325let end = self.required_of_allow.len();13261327self.allow.insert(1328id,1329Explicit {1330insert_mode,1331required_range: Some(start..end),1332},1333);1334}1335}13361337/// Contains the components explicitly allowed to be cloned.1338struct Explicit {1339/// If component was added via [`allow`](EntityClonerBuilder::allow) etc, this is `Overwrite`.1340///1341/// If component was added via [`allow_if_new`](EntityClonerBuilder::allow_if_new) etc, this is `Keep`.1342insert_mode: InsertMode,13431344/// Contains the range in [`OptIn::required_of_allow`] for this component containing its1345/// required components.1346///1347/// Is `None` if [`OptIn::attach_required_components`] was `false` when added.1348/// It may be set to `Some` later if the component is later added explicitly again with1349/// [`OptIn::attach_required_components`] being `true`.1350///1351/// Range is empty if this component has no required components that are not also explicitly allowed.1352required_range: Option<Range<usize>>,1353}13541355struct Required {1356/// Amount of explicit components this component is required by.1357required_by: u32,13581359/// As [`Self::required_by`] but is reduced during cloning when an explicit component is not cloned,1360/// either because [`Explicit::insert_mode`] is `Keep` or the source entity does not contain it.1361///1362/// If this is zero, the required component is not cloned.1363///1364/// The counter is reset to `required_by` when the cloning is over in case another entity needs to be1365/// cloned by the same [`EntityCloner`].1366required_by_reduced: u32,1367}13681369impl Required {1370// Revert reductions for the next entity to clone with this EntityCloner1371#[inline]1372fn reset(&mut self) {1373self.required_by_reduced = self.required_by;1374}1375}13761377mod private {1378use crate::{bundle::BundleId, component::ComponentId};1379use core::any::TypeId;1380use derive_more::From;13811382/// Marker trait to allow multiple blanket implementations for [`FilterableIds`].1383pub trait Marker {}1384/// Marker struct for [`FilterableIds`] implementation for single-value types.1385pub struct ScalarType {}1386impl Marker for ScalarType {}1387/// Marker struct for [`FilterableIds`] implementation for [`IntoIterator`] types.1388pub struct VectorType {}1389impl Marker for VectorType {}13901391/// Defines types of ids that [`EntityClonerBuilder`](`super::EntityClonerBuilder`) can filter components by.1392#[derive(From)]1393pub enum FilterableId {1394Type(TypeId),1395Component(ComponentId),1396Bundle(BundleId),1397}13981399impl<'a, T> From<&'a T> for FilterableId1400where1401T: Into<FilterableId> + Copy,1402{1403#[inline]1404fn from(value: &'a T) -> Self {1405(*value).into()1406}1407}14081409/// A trait to allow [`EntityClonerBuilder`](`super::EntityClonerBuilder`) filter by any supported id type and their iterators,1410/// reducing the number of method permutations required for all id types.1411///1412/// The supported id types that can be used to filter components are defined by [`FilterableId`], which allows following types: [`TypeId`], [`ComponentId`] and [`BundleId`].1413///1414/// `M` is a generic marker to allow multiple blanket implementations of this trait.1415/// This works because `FilterableId<M1>` is a different trait from `FilterableId<M2>`, so multiple blanket implementations for different `M` are allowed.1416/// The reason this is required is because supporting `IntoIterator` requires blanket implementation, but that will conflict with implementation for `TypeId`1417/// since `IntoIterator` can technically be implemented for `TypeId` in the future.1418/// Functions like `allow_by_ids` rely on type inference to automatically select proper type for `M` at call site.1419pub trait FilterableIds<M: Marker> {1420/// Takes in a function that processes all types of [`FilterableId`] one-by-one.1421fn filter_ids(self, ids: &mut impl FnMut(FilterableId));1422}14231424impl<I, T> FilterableIds<VectorType> for I1425where1426I: IntoIterator<Item = T>,1427T: Into<FilterableId>,1428{1429#[inline]1430fn filter_ids(self, ids: &mut impl FnMut(FilterableId)) {1431for id in self.into_iter() {1432ids(id.into());1433}1434}1435}14361437impl<T> FilterableIds<ScalarType> for T1438where1439T: Into<FilterableId>,1440{1441#[inline]1442fn filter_ids(self, ids: &mut impl FnMut(FilterableId)) {1443ids(self.into());1444}1445}1446}14471448use private::{FilterableId, FilterableIds, Marker};14491450#[cfg(test)]1451mod tests {1452use super::*;1453use crate::{1454component::{ComponentDescriptor, StorageType},1455lifecycle::HookContext,1456prelude::{ChildOf, Children, Resource},1457world::{DeferredWorld, FromWorld, World},1458};1459use bevy_ptr::OwningPtr;1460use core::marker::PhantomData;1461use core::{alloc::Layout, ops::Deref};14621463#[cfg(feature = "bevy_reflect")]1464mod reflect {1465use super::*;1466use crate::reflect::{AppTypeRegistry, ReflectComponent, ReflectFromWorld};1467use alloc::vec;1468use bevy_reflect::{std_traits::ReflectDefault, FromType, Reflect, ReflectFromPtr};14691470#[test]1471fn clone_entity_using_reflect() {1472#[derive(Component, Reflect, Clone, PartialEq, Eq)]1473#[reflect(Component)]1474struct A {1475field: usize,1476}14771478let mut world = World::default();1479world.init_resource::<AppTypeRegistry>();1480let registry = world.get_resource::<AppTypeRegistry>().unwrap();1481registry.write().register::<A>();14821483world.register_component::<A>();1484let component = A { field: 5 };14851486let e = world.spawn(component.clone()).id();1487let e_clone = world.spawn_empty().id();14881489EntityCloner::build_opt_out(&mut world)1490.override_clone_behavior::<A>(ComponentCloneBehavior::reflect())1491.clone_entity(e, e_clone);14921493assert!(world.get::<A>(e_clone).is_some_and(|c| *c == component));1494}14951496#[test]1497fn clone_entity_using_reflect_all_paths() {1498#[derive(PartialEq, Eq, Default, Debug)]1499struct NotClone;15001501// `reflect_clone`-based fast path1502#[derive(Component, Reflect, PartialEq, Eq, Default, Debug)]1503#[reflect(from_reflect = false)]1504struct A {1505field: usize,1506field2: Vec<usize>,1507}15081509// `ReflectDefault`-based fast path1510#[derive(Component, Reflect, PartialEq, Eq, Default, Debug)]1511#[reflect(Default)]1512#[reflect(from_reflect = false)]1513struct B {1514field: usize,1515field2: Vec<usize>,1516#[reflect(ignore)]1517ignored: NotClone,1518}15191520// `ReflectFromReflect`-based fast path1521#[derive(Component, Reflect, PartialEq, Eq, Default, Debug)]1522struct C {1523field: usize,1524field2: Vec<usize>,1525#[reflect(ignore)]1526ignored: NotClone,1527}15281529// `ReflectFromWorld`-based fast path1530#[derive(Component, Reflect, PartialEq, Eq, Default, Debug)]1531#[reflect(FromWorld)]1532#[reflect(from_reflect = false)]1533struct D {1534field: usize,1535field2: Vec<usize>,1536#[reflect(ignore)]1537ignored: NotClone,1538}15391540let mut world = World::default();1541world.init_resource::<AppTypeRegistry>();1542let registry = world.get_resource::<AppTypeRegistry>().unwrap();1543registry.write().register::<(A, B, C, D)>();15441545let a_id = world.register_component::<A>();1546let b_id = world.register_component::<B>();1547let c_id = world.register_component::<C>();1548let d_id = world.register_component::<D>();1549let component_a = A {1550field: 5,1551field2: vec![1, 2, 3, 4, 5],1552};1553let component_b = B {1554field: 5,1555field2: vec![1, 2, 3, 4, 5],1556ignored: NotClone,1557};1558let component_c = C {1559field: 6,1560field2: vec![1, 2, 3, 4, 5],1561ignored: NotClone,1562};1563let component_d = D {1564field: 7,1565field2: vec![1, 2, 3, 4, 5],1566ignored: NotClone,1567};15681569let e = world1570.spawn((component_a, component_b, component_c, component_d))1571.id();1572let e_clone = world.spawn_empty().id();15731574EntityCloner::build_opt_out(&mut world)1575.override_clone_behavior_with_id(a_id, ComponentCloneBehavior::reflect())1576.override_clone_behavior_with_id(b_id, ComponentCloneBehavior::reflect())1577.override_clone_behavior_with_id(c_id, ComponentCloneBehavior::reflect())1578.override_clone_behavior_with_id(d_id, ComponentCloneBehavior::reflect())1579.clone_entity(e, e_clone);15801581assert_eq!(world.get::<A>(e_clone), Some(world.get::<A>(e).unwrap()));1582assert_eq!(world.get::<B>(e_clone), Some(world.get::<B>(e).unwrap()));1583assert_eq!(world.get::<C>(e_clone), Some(world.get::<C>(e).unwrap()));1584assert_eq!(world.get::<D>(e_clone), Some(world.get::<D>(e).unwrap()));1585}15861587#[test]1588fn read_source_component_reflect_should_return_none_on_invalid_reflect_from_ptr() {1589#[derive(Component, Reflect)]1590struct A;15911592#[derive(Component, Reflect)]1593struct B;15941595fn test_handler(source: &SourceComponent, ctx: &mut ComponentCloneCtx) {1596let registry = ctx.type_registry().unwrap();1597assert!(source.read_reflect(®istry.read()).is_none());1598}15991600let mut world = World::default();1601world.init_resource::<AppTypeRegistry>();1602let registry = world.get_resource::<AppTypeRegistry>().unwrap();1603{1604let mut registry = registry.write();1605registry.register::<A>();1606registry1607.get_mut(TypeId::of::<A>())1608.unwrap()1609.insert(<ReflectFromPtr as FromType<B>>::from_type());1610}16111612let e = world.spawn(A).id();1613let e_clone = world.spawn_empty().id();16141615EntityCloner::build_opt_out(&mut world)1616.override_clone_behavior::<A>(ComponentCloneBehavior::Custom(test_handler))1617.clone_entity(e, e_clone);1618}16191620#[test]1621fn clone_entity_specialization() {1622#[derive(Component, Reflect, PartialEq, Eq)]1623#[reflect(Component)]1624struct A {1625field: usize,1626}16271628impl Clone for A {1629fn clone(&self) -> Self {1630Self { field: 10 }1631}1632}16331634let mut world = World::default();1635world.init_resource::<AppTypeRegistry>();1636let registry = world.get_resource::<AppTypeRegistry>().unwrap();1637registry.write().register::<A>();16381639let component = A { field: 5 };16401641let e = world.spawn(component.clone()).id();1642let e_clone = world.spawn_empty().id();16431644EntityCloner::build_opt_out(&mut world).clone_entity(e, e_clone);16451646assert!(world1647.get::<A>(e_clone)1648.is_some_and(|comp| *comp == A { field: 10 }));1649}16501651#[test]1652fn clone_entity_using_reflect_should_skip_without_panic() {1653// Not reflected1654#[derive(Component, PartialEq, Eq, Default, Debug)]1655struct A;16561657// No valid type data and not `reflect_clone`-able1658#[derive(Component, Reflect, PartialEq, Eq, Default, Debug)]1659#[reflect(Component)]1660#[reflect(from_reflect = false)]1661struct B(#[reflect(ignore)] PhantomData<()>);16621663let mut world = World::default();16641665// No AppTypeRegistry1666let e = world.spawn((A, B(Default::default()))).id();1667let e_clone = world.spawn_empty().id();1668EntityCloner::build_opt_out(&mut world)1669.override_clone_behavior::<A>(ComponentCloneBehavior::reflect())1670.override_clone_behavior::<B>(ComponentCloneBehavior::reflect())1671.clone_entity(e, e_clone);1672assert_eq!(world.get::<A>(e_clone), None);1673assert_eq!(world.get::<B>(e_clone), None);16741675// With AppTypeRegistry1676world.init_resource::<AppTypeRegistry>();1677let registry = world.get_resource::<AppTypeRegistry>().unwrap();1678registry.write().register::<B>();16791680let e = world.spawn((A, B(Default::default()))).id();1681let e_clone = world.spawn_empty().id();1682EntityCloner::build_opt_out(&mut world).clone_entity(e, e_clone);1683assert_eq!(world.get::<A>(e_clone), None);1684assert_eq!(world.get::<B>(e_clone), None);1685}16861687#[test]1688fn clone_with_reflect_from_world() {1689#[derive(Component, Reflect, PartialEq, Eq, Debug)]1690#[reflect(Component, FromWorld, from_reflect = false)]1691struct SomeRef(1692#[entities] Entity,1693// We add an ignored field here to ensure `reflect_clone` fails and `FromWorld` is used1694#[reflect(ignore)] PhantomData<()>,1695);16961697#[derive(Resource)]1698struct FromWorldCalled(bool);16991700impl FromWorld for SomeRef {1701fn from_world(world: &mut World) -> Self {1702world.insert_resource(FromWorldCalled(true));1703SomeRef(Entity::PLACEHOLDER, Default::default())1704}1705}1706let mut world = World::new();1707let registry = AppTypeRegistry::default();1708registry.write().register::<SomeRef>();1709world.insert_resource(registry);17101711let a = world.spawn_empty().id();1712let b = world.spawn_empty().id();1713let c = world.spawn(SomeRef(a, Default::default())).id();1714let d = world.spawn_empty().id();1715let mut map = EntityHashMap::<Entity>::new();1716map.insert(a, b);1717map.insert(c, d);17181719let cloned = EntityCloner::default().clone_entity_mapped(&mut world, c, &mut map);1720assert_eq!(1721*world.entity(cloned).get::<SomeRef>().unwrap(),1722SomeRef(b, Default::default())1723);1724assert!(world.resource::<FromWorldCalled>().0);1725}1726}17271728#[test]1729fn clone_entity_using_clone() {1730#[derive(Component, Clone, PartialEq, Eq)]1731struct A {1732field: usize,1733}17341735let mut world = World::default();17361737let component = A { field: 5 };17381739let e = world.spawn(component.clone()).id();1740let e_clone = world.spawn_empty().id();17411742EntityCloner::build_opt_out(&mut world).clone_entity(e, e_clone);17431744assert!(world.get::<A>(e_clone).is_some_and(|c| *c == component));1745}17461747#[test]1748fn clone_entity_with_allow_filter() {1749#[derive(Component, Clone, PartialEq, Eq)]1750struct A {1751field: usize,1752}17531754#[derive(Component, Clone)]1755struct B;17561757let mut world = World::default();17581759let component = A { field: 5 };17601761let e = world.spawn((component.clone(), B)).id();1762let e_clone = world.spawn_empty().id();17631764EntityCloner::build_opt_in(&mut world)1765.allow::<A>()1766.clone_entity(e, e_clone);17671768assert!(world.get::<A>(e_clone).is_some_and(|c| *c == component));1769assert!(world.get::<B>(e_clone).is_none());1770}17711772#[test]1773fn clone_entity_with_deny_filter() {1774#[derive(Component, Clone, PartialEq, Eq)]1775struct A {1776field: usize,1777}17781779#[derive(Component, Clone)]1780#[require(C)]1781struct B;17821783#[derive(Component, Clone, Default)]1784struct C;17851786let mut world = World::default();17871788let component = A { field: 5 };17891790let e = world.spawn((component.clone(), B, C)).id();1791let e_clone = world.spawn_empty().id();17921793EntityCloner::build_opt_out(&mut world)1794.deny::<C>()1795.clone_entity(e, e_clone);17961797assert!(world.get::<A>(e_clone).is_some_and(|c| *c == component));1798assert!(world.get::<B>(e_clone).is_none());1799assert!(world.get::<C>(e_clone).is_none());1800}18011802#[test]1803fn clone_entity_with_deny_filter_without_required_by() {1804#[derive(Component, Clone)]1805#[require(B { field: 5 })]1806struct A;18071808#[derive(Component, Clone, PartialEq, Eq)]1809struct B {1810field: usize,1811}18121813let mut world = World::default();18141815let e = world.spawn((A, B { field: 10 })).id();1816let e_clone = world.spawn_empty().id();18171818EntityCloner::build_opt_out(&mut world)1819.without_required_by_components(|builder| {1820builder.deny::<B>();1821})1822.clone_entity(e, e_clone);18231824assert!(world.get::<A>(e_clone).is_some());1825assert!(world1826.get::<B>(e_clone)1827.is_some_and(|c| *c == B { field: 5 }));1828}18291830#[test]1831fn clone_entity_with_deny_filter_if_new() {1832#[derive(Component, Clone, PartialEq, Eq)]1833struct A {1834field: usize,1835}18361837#[derive(Component, Clone)]1838struct B;18391840#[derive(Component, Clone)]1841struct C;18421843let mut world = World::default();18441845let e = world.spawn((A { field: 5 }, B, C)).id();1846let e_clone = world.spawn(A { field: 8 }).id();18471848EntityCloner::build_opt_out(&mut world)1849.deny::<B>()1850.insert_mode(InsertMode::Keep)1851.clone_entity(e, e_clone);18521853assert!(world1854.get::<A>(e_clone)1855.is_some_and(|c| *c == A { field: 8 }));1856assert!(world.get::<B>(e_clone).is_none());1857assert!(world.get::<C>(e_clone).is_some());1858}18591860#[test]1861fn allow_and_allow_if_new_always_allows() {1862#[derive(Component, Clone, PartialEq, Debug)]1863struct A(u8);18641865let mut world = World::default();1866let e = world.spawn(A(1)).id();1867let e_clone1 = world.spawn(A(2)).id();18681869EntityCloner::build_opt_in(&mut world)1870.allow_if_new::<A>()1871.allow::<A>()1872.clone_entity(e, e_clone1);18731874assert_eq!(world.get::<A>(e_clone1), Some(&A(1)));18751876let e_clone2 = world.spawn(A(2)).id();18771878EntityCloner::build_opt_in(&mut world)1879.allow::<A>()1880.allow_if_new::<A>()1881.clone_entity(e, e_clone2);18821883assert_eq!(world.get::<A>(e_clone2), Some(&A(1)));1884}18851886#[test]1887fn with_and_without_required_components_include_required() {1888#[derive(Component, Clone, PartialEq, Debug)]1889#[require(B(5))]1890struct A;18911892#[derive(Component, Clone, PartialEq, Debug)]1893struct B(u8);18941895let mut world = World::default();1896let e = world.spawn((A, B(10))).id();1897let e_clone1 = world.spawn_empty().id();1898EntityCloner::build_opt_in(&mut world)1899.without_required_components(|builder| {1900builder.allow::<A>();1901})1902.allow::<A>()1903.clone_entity(e, e_clone1);19041905assert_eq!(world.get::<B>(e_clone1), Some(&B(10)));19061907let e_clone2 = world.spawn_empty().id();19081909EntityCloner::build_opt_in(&mut world)1910.allow::<A>()1911.without_required_components(|builder| {1912builder.allow::<A>();1913})1914.clone_entity(e, e_clone2);19151916assert_eq!(world.get::<B>(e_clone2), Some(&B(10)));1917}19181919#[test]1920fn clone_required_becoming_explicit() {1921#[derive(Component, Clone, PartialEq, Debug)]1922#[require(B(5))]1923struct A;19241925#[derive(Component, Clone, PartialEq, Debug)]1926struct B(u8);19271928let mut world = World::default();1929let e = world.spawn((A, B(10))).id();1930let e_clone1 = world.spawn(B(20)).id();1931EntityCloner::build_opt_in(&mut world)1932.allow::<A>()1933.allow::<B>()1934.clone_entity(e, e_clone1);19351936assert_eq!(world.get::<B>(e_clone1), Some(&B(10)));19371938let e_clone2 = world.spawn(B(20)).id();1939EntityCloner::build_opt_in(&mut world)1940.allow::<A>()1941.allow::<B>()1942.clone_entity(e, e_clone2);19431944assert_eq!(world.get::<B>(e_clone2), Some(&B(10)));1945}19461947#[test]1948fn required_not_cloned_because_requiring_missing() {1949#[derive(Component, Clone)]1950#[require(B)]1951struct A;19521953#[derive(Component, Clone, Default)]1954struct B;19551956let mut world = World::default();1957let e = world.spawn(B).id();1958let e_clone1 = world.spawn_empty().id();19591960EntityCloner::build_opt_in(&mut world)1961.allow::<A>()1962.clone_entity(e, e_clone1);19631964assert!(world.get::<B>(e_clone1).is_none());1965}19661967#[test]1968fn clone_entity_with_required_components() {1969#[derive(Component, Clone, PartialEq, Debug)]1970#[require(B)]1971struct A;19721973#[derive(Component, Clone, PartialEq, Debug, Default)]1974#[require(C(5))]1975struct B;19761977#[derive(Component, Clone, PartialEq, Debug)]1978struct C(u32);19791980let mut world = World::default();19811982let e = world.spawn(A).id();1983let e_clone = world.spawn_empty().id();19841985EntityCloner::build_opt_in(&mut world)1986.allow::<B>()1987.clone_entity(e, e_clone);19881989assert_eq!(world.entity(e_clone).get::<A>(), None);1990assert_eq!(world.entity(e_clone).get::<B>(), Some(&B));1991assert_eq!(world.entity(e_clone).get::<C>(), Some(&C(5)));1992}19931994#[test]1995fn clone_entity_with_default_required_components() {1996#[derive(Component, Clone, PartialEq, Debug)]1997#[require(B)]1998struct A;19992000#[derive(Component, Clone, PartialEq, Debug, Default)]2001#[require(C(5))]2002struct B;20032004#[derive(Component, Clone, PartialEq, Debug)]2005struct C(u32);20062007let mut world = World::default();20082009let e = world.spawn((A, C(0))).id();2010let e_clone = world.spawn_empty().id();20112012EntityCloner::build_opt_in(&mut world)2013.without_required_components(|builder| {2014builder.allow::<A>();2015})2016.clone_entity(e, e_clone);20172018assert_eq!(world.entity(e_clone).get::<A>(), Some(&A));2019assert_eq!(world.entity(e_clone).get::<B>(), Some(&B));2020assert_eq!(world.entity(e_clone).get::<C>(), Some(&C(5)));2021}20222023#[test]2024fn clone_entity_with_missing_required_components() {2025#[derive(Component, Clone, PartialEq, Debug)]2026#[require(B)]2027struct A;20282029#[derive(Component, Clone, PartialEq, Debug, Default)]2030#[require(C(5))]2031struct B;20322033#[derive(Component, Clone, PartialEq, Debug)]2034struct C(u32);20352036let mut world = World::default();20372038let e = world.spawn(A).remove::<C>().id();2039let e_clone = world.spawn_empty().id();20402041EntityCloner::build_opt_in(&mut world)2042.allow::<A>()2043.clone_entity(e, e_clone);20442045assert_eq!(world.entity(e_clone).get::<A>(), Some(&A));2046assert_eq!(world.entity(e_clone).get::<B>(), Some(&B));2047assert_eq!(world.entity(e_clone).get::<C>(), Some(&C(5)));2048}20492050#[test]2051fn skipped_required_components_counter_is_reset_on_early_return() {2052#[derive(Component, Clone, PartialEq, Debug, Default)]2053#[require(B(5))]2054struct A;20552056#[derive(Component, Clone, PartialEq, Debug)]2057struct B(u32);20582059#[derive(Component, Clone, PartialEq, Debug, Default)]2060struct C;20612062let mut world = World::default();20632064let e1 = world.spawn(C).id();2065let e2 = world.spawn((A, B(0))).id();2066let e_clone = world.spawn_empty().id();20672068let mut builder = EntityCloner::build_opt_in(&mut world);2069builder.allow::<(A, C)>();2070let mut cloner = builder.finish();2071cloner.clone_entity(&mut world, e1, e_clone);2072cloner.clone_entity(&mut world, e2, e_clone);20732074assert_eq!(world.entity(e_clone).get::<B>(), Some(&B(0)));2075}20762077#[test]2078fn clone_entity_with_dynamic_components() {2079const COMPONENT_SIZE: usize = 10;2080fn test_handler(source: &SourceComponent, ctx: &mut ComponentCloneCtx) {2081// SAFETY: the passed in ptr corresponds to copy-able data that matches the type of the source / target component2082unsafe {2083ctx.write_target_component_ptr(source.ptr());2084}2085}20862087let mut world = World::default();20882089let layout = Layout::array::<u8>(COMPONENT_SIZE).unwrap();2090// SAFETY:2091// - No drop command is required2092// - The component will store [u8; COMPONENT_SIZE], which is Send + Sync2093let descriptor = unsafe {2094ComponentDescriptor::new_with_layout(2095"DynamicComp",2096StorageType::Table,2097layout,2098None,2099true,2100ComponentCloneBehavior::Custom(test_handler),2101)2102};2103let component_id = world.register_component_with_descriptor(descriptor);21042105let mut entity = world.spawn_empty();2106let data = [5u8; COMPONENT_SIZE];21072108// SAFETY:2109// - ptr points to data represented by component_id ([u8; COMPONENT_SIZE])2110// - component_id is from the same world as entity2111OwningPtr::make(data, |ptr| unsafe {2112entity.insert_by_id(component_id, ptr);2113});2114let entity = entity.id();21152116let entity_clone = world.spawn_empty().id();2117EntityCloner::build_opt_out(&mut world).clone_entity(entity, entity_clone);21182119let ptr = world.get_by_id(entity, component_id).unwrap();2120let clone_ptr = world.get_by_id(entity_clone, component_id).unwrap();2121// SAFETY: ptr and clone_ptr store component represented by [u8; COMPONENT_SIZE]2122unsafe {2123assert_eq!(2124core::slice::from_raw_parts(ptr.as_ptr(), COMPONENT_SIZE),2125core::slice::from_raw_parts(clone_ptr.as_ptr(), COMPONENT_SIZE),2126);2127}2128}21292130#[test]2131fn recursive_clone() {2132let mut world = World::new();2133let root = world.spawn_empty().id();2134let child1 = world.spawn(ChildOf(root)).id();2135let grandchild = world.spawn(ChildOf(child1)).id();2136let child2 = world.spawn(ChildOf(root)).id();21372138let clone_root = world.spawn_empty().id();2139EntityCloner::build_opt_out(&mut world)2140.linked_cloning(true)2141.clone_entity(root, clone_root);21422143let root_children = world2144.entity(clone_root)2145.get::<Children>()2146.unwrap()2147.iter()2148.cloned()2149.collect::<Vec<_>>();21502151assert!(root_children.iter().all(|e| *e != child1 && *e != child2));2152assert_eq!(root_children.len(), 2);2153assert_eq!(2154(2155world.get::<ChildOf>(root_children[0]),2156world.get::<ChildOf>(root_children[1])2157),2158(Some(&ChildOf(clone_root)), Some(&ChildOf(clone_root)))2159);2160let child1_children = world.entity(root_children[0]).get::<Children>().unwrap();2161assert_eq!(child1_children.len(), 1);2162assert_ne!(child1_children[0], grandchild);2163assert!(world.entity(root_children[1]).get::<Children>().is_none());2164assert_eq!(2165world.get::<ChildOf>(child1_children[0]),2166Some(&ChildOf(root_children[0]))2167);21682169assert_eq!(2170world.entity(root).get::<Children>().unwrap().deref(),2171&[child1, child2]2172);2173}21742175#[test]2176fn cloning_with_required_components_preserves_existing() {2177#[derive(Component, Clone, PartialEq, Debug, Default)]2178#[require(B(5))]2179struct A;21802181#[derive(Component, Clone, PartialEq, Debug)]2182struct B(u32);21832184let mut world = World::default();21852186let e = world.spawn((A, B(0))).id();2187let e_clone = world.spawn(B(1)).id();21882189EntityCloner::build_opt_in(&mut world)2190.allow::<A>()2191.clone_entity(e, e_clone);21922193assert_eq!(world.entity(e_clone).get::<A>(), Some(&A));2194assert_eq!(world.entity(e_clone).get::<B>(), Some(&B(1)));2195}21962197#[test]2198fn move_without_clone() {2199#[derive(Component, PartialEq, Debug)]2200#[component(storage = "SparseSet")]2201struct A;22022203#[derive(Component, PartialEq, Debug)]2204struct B(Vec<u8>);22052206let mut world = World::default();2207let e = world.spawn((A, B(alloc::vec![1, 2, 3]))).id();2208let e_clone = world.spawn_empty().id();2209let mut builder = EntityCloner::build_opt_out(&mut world);2210builder.move_components(true);2211let mut cloner = builder.finish();22122213cloner.clone_entity(&mut world, e, e_clone);22142215assert_eq!(world.get::<A>(e), None);2216assert_eq!(world.get::<B>(e), None);22172218assert_eq!(world.get::<A>(e_clone), Some(&A));2219assert_eq!(world.get::<B>(e_clone), Some(&B(alloc::vec![1, 2, 3])));2220}22212222#[test]2223fn move_with_remove_hook() {2224#[derive(Component, PartialEq, Debug)]2225#[component(on_remove=remove_hook)]2226struct B(Option<Vec<u8>>);22272228fn remove_hook(mut world: DeferredWorld, ctx: HookContext) {2229world.get_mut::<B>(ctx.entity).unwrap().0.take();2230}22312232let mut world = World::default();2233let e = world.spawn(B(Some(alloc::vec![1, 2, 3]))).id();2234let e_clone = world.spawn_empty().id();2235let mut builder = EntityCloner::build_opt_out(&mut world);2236builder.move_components(true);2237let mut cloner = builder.finish();22382239cloner.clone_entity(&mut world, e, e_clone);22402241assert_eq!(world.get::<B>(e), None);2242assert_eq!(world.get::<B>(e_clone), Some(&B(None)));2243}22442245#[test]2246fn move_with_deferred() {2247#[derive(Component, PartialEq, Debug)]2248#[component(clone_behavior=Custom(custom))]2249struct A(u32);22502251#[derive(Component, PartialEq, Debug)]2252struct B(u32);22532254fn custom(_src: &SourceComponent, ctx: &mut ComponentCloneCtx) {2255// Clone using deferred2256let source = ctx.source();2257ctx.queue_deferred(move |world, mapper| {2258let target = mapper.get_mapped(source);2259world.entity_mut(target).insert(A(10));2260});2261}22622263let mut world = World::default();2264let e = world.spawn((A(0), B(1))).id();2265let e_clone = world.spawn_empty().id();2266let mut builder = EntityCloner::build_opt_out(&mut world);2267builder.move_components(true);2268let mut cloner = builder.finish();22692270cloner.clone_entity(&mut world, e, e_clone);22712272assert_eq!(world.get::<A>(e), None);2273assert_eq!(world.get::<A>(e_clone), Some(&A(10)));2274assert_eq!(world.get::<B>(e), None);2275assert_eq!(world.get::<B>(e_clone), Some(&B(1)));2276}22772278#[test]2279fn move_relationship() {2280#[derive(Component, Clone, PartialEq, Eq, Debug)]2281#[relationship(relationship_target=Target)]2282struct Source(Entity);22832284#[derive(Component, Clone, PartialEq, Eq, Debug)]2285#[relationship_target(relationship=Source)]2286struct Target(Vec<Entity>);22872288#[derive(Component, PartialEq, Debug)]2289struct A(u32);22902291let mut world = World::default();2292let e_target = world.spawn(A(1)).id();2293let e_source = world.spawn((A(2), Source(e_target))).id();22942295let mut builder = EntityCloner::build_opt_out(&mut world);2296builder.move_components(true);2297let mut cloner = builder.finish();22982299let e_source_moved = world.spawn_empty().id();23002301cloner.clone_entity(&mut world, e_source, e_source_moved);23022303assert_eq!(world.get::<A>(e_source), None);2304assert_eq!(world.get::<A>(e_source_moved), Some(&A(2)));2305assert_eq!(world.get::<Source>(e_source), None);2306assert_eq!(world.get::<Source>(e_source_moved), Some(&Source(e_target)));2307assert_eq!(2308world.get::<Target>(e_target),2309Some(&Target(alloc::vec![e_source_moved]))2310);23112312let e_target_moved = world.spawn_empty().id();23132314cloner.clone_entity(&mut world, e_target, e_target_moved);23152316assert_eq!(world.get::<A>(e_target), None);2317assert_eq!(world.get::<A>(e_target_moved), Some(&A(1)));2318assert_eq!(world.get::<Target>(e_target), None);2319assert_eq!(2320world.get::<Target>(e_target_moved),2321Some(&Target(alloc::vec![e_source_moved]))2322);2323assert_eq!(2324world.get::<Source>(e_source_moved),2325Some(&Source(e_target_moved))2326);2327}23282329#[test]2330fn move_hierarchy() {2331#[derive(Component, PartialEq, Debug)]2332struct A(u32);23332334let mut world = World::default();2335let e_parent = world.spawn(A(1)).id();2336let e_child1 = world.spawn((A(2), ChildOf(e_parent))).id();2337let e_child2 = world.spawn((A(3), ChildOf(e_parent))).id();2338let e_child1_1 = world.spawn((A(4), ChildOf(e_child1))).id();23392340let e_parent_clone = world.spawn_empty().id();23412342let mut builder = EntityCloner::build_opt_out(&mut world);2343builder.move_components(true).linked_cloning(true);2344let mut cloner = builder.finish();23452346cloner.clone_entity(&mut world, e_parent, e_parent_clone);23472348assert_eq!(world.get::<A>(e_parent), None);2349assert_eq!(world.get::<A>(e_child1), None);2350assert_eq!(world.get::<A>(e_child2), None);2351assert_eq!(world.get::<A>(e_child1_1), None);23522353let mut children = world.get::<Children>(e_parent_clone).unwrap().iter();2354let e_child1_clone = *children.next().unwrap();2355let e_child2_clone = *children.next().unwrap();2356let mut children = world.get::<Children>(e_child1_clone).unwrap().iter();2357let e_child1_1_clone = *children.next().unwrap();23582359assert_eq!(world.get::<A>(e_parent_clone), Some(&A(1)));2360assert_eq!(world.get::<A>(e_child1_clone), Some(&A(2)));2361assert_eq!(2362world.get::<ChildOf>(e_child1_clone),2363Some(&ChildOf(e_parent_clone))2364);2365assert_eq!(world.get::<A>(e_child2_clone), Some(&A(3)));2366assert_eq!(2367world.get::<ChildOf>(e_child2_clone),2368Some(&ChildOf(e_parent_clone))2369);2370assert_eq!(world.get::<A>(e_child1_1_clone), Some(&A(4)));2371assert_eq!(2372world.get::<ChildOf>(e_child1_1_clone),2373Some(&ChildOf(e_child1_clone))2374);2375}23762377// Original: E1 Target{target: [E2], data: [4,5,6]}2378// | E2 Source{target: E1, data: [1,2,3]}2379//2380// Cloned: E3 Target{target: [], data: [4,5,6]}2381#[test]2382fn clone_relationship_with_data() {2383#[derive(Component, Clone)]2384#[relationship(relationship_target=Target)]2385struct Source {2386#[relationship]2387target: Entity,2388data: Vec<u8>,2389}23902391#[derive(Component, Clone)]2392#[relationship_target(relationship=Source)]2393struct Target {2394#[relationship]2395target: Vec<Entity>,2396data: Vec<u8>,2397}23982399let mut world = World::default();2400let e_target = world.spawn_empty().id();2401let e_source = world2402.spawn(Source {2403target: e_target,2404data: alloc::vec![1, 2, 3],2405})2406.id();2407world.get_mut::<Target>(e_target).unwrap().data = alloc::vec![4, 5, 6];24082409let builder = EntityCloner::build_opt_out(&mut world);2410let mut cloner = builder.finish();24112412let e_target_clone = world.spawn_empty().id();2413cloner.clone_entity(&mut world, e_target, e_target_clone);24142415let target = world.get::<Target>(e_target).unwrap();2416let cloned_target = world.get::<Target>(e_target_clone).unwrap();24172418assert_eq!(cloned_target.data, target.data);2419assert_eq!(target.target, alloc::vec![e_source]);2420assert_eq!(cloned_target.target.len(), 0);24212422let source = world.get::<Source>(e_source).unwrap();24232424assert_eq!(source.data, alloc::vec![1, 2, 3]);2425}24262427// Original: E1 Target{target: [E2], data: [4,5,6]}2428// | E2 Source{target: E1, data: [1,2,3]}2429//2430// Cloned: E3 Target{target: [E4], data: [4,5,6]}2431// | E4 Source{target: E3, data: [1,2,3]}2432#[test]2433fn clone_linked_relationship_with_data() {2434#[derive(Component, Clone)]2435#[relationship(relationship_target=Target)]2436struct Source {2437#[relationship]2438target: Entity,2439data: Vec<u8>,2440}24412442#[derive(Component, Clone)]2443#[relationship_target(relationship=Source, linked_spawn)]2444struct Target {2445#[relationship]2446target: Vec<Entity>,2447data: Vec<u8>,2448}24492450let mut world = World::default();2451let e_target = world.spawn_empty().id();2452let e_source = world2453.spawn(Source {2454target: e_target,2455data: alloc::vec![1, 2, 3],2456})2457.id();2458world.get_mut::<Target>(e_target).unwrap().data = alloc::vec![4, 5, 6];24592460let mut builder = EntityCloner::build_opt_out(&mut world);2461builder.linked_cloning(true);2462let mut cloner = builder.finish();24632464let e_target_clone = world.spawn_empty().id();2465cloner.clone_entity(&mut world, e_target, e_target_clone);24662467let target = world.get::<Target>(e_target).unwrap();2468let cloned_target = world.get::<Target>(e_target_clone).unwrap();24692470assert_eq!(cloned_target.data, target.data);2471assert_eq!(target.target, alloc::vec![e_source]);2472assert_eq!(cloned_target.target.len(), 1);24732474let source = world.get::<Source>(e_source).unwrap();2475let cloned_source = world.get::<Source>(cloned_target.target[0]).unwrap();24762477assert_eq!(cloned_source.data, source.data);2478assert_eq!(source.target, e_target);2479assert_eq!(cloned_source.target, e_target_clone);2480}24812482// Original: E12483// E22484//2485// Moved: E3 Target{target: [], data: [4,5,6]}2486#[test]2487fn move_relationship_with_data() {2488#[derive(Component, Clone, PartialEq, Eq, Debug)]2489#[relationship(relationship_target=Target)]2490struct Source {2491#[relationship]2492target: Entity,2493data: Vec<u8>,2494}24952496#[derive(Component, Clone, PartialEq, Eq, Debug)]2497#[relationship_target(relationship=Source)]2498struct Target {2499#[relationship]2500target: Vec<Entity>,2501data: Vec<u8>,2502}25032504let source_data = alloc::vec![1, 2, 3];2505let target_data = alloc::vec![4, 5, 6];25062507let mut world = World::default();2508let e_target = world.spawn_empty().id();2509let e_source = world2510.spawn(Source {2511target: e_target,2512data: source_data.clone(),2513})2514.id();2515world.get_mut::<Target>(e_target).unwrap().data = target_data.clone();25162517let mut builder = EntityCloner::build_opt_out(&mut world);2518builder.move_components(true);2519let mut cloner = builder.finish();25202521let e_target_moved = world.spawn_empty().id();2522cloner.clone_entity(&mut world, e_target, e_target_moved);25232524assert_eq!(world.get::<Target>(e_target), None);2525assert_eq!(2526world.get::<Source>(e_source),2527Some(&Source {2528data: source_data,2529target: e_target_moved,2530})2531);2532assert_eq!(2533world.get::<Target>(e_target_moved),2534Some(&Target {2535target: alloc::vec![e_source],2536data: target_data2537})2538);2539}25402541// Original: E12542// E22543//2544// Moved: E3 Target{target: [E4], data: [4,5,6]}2545// | E4 Source{target: E3, data: [1,2,3]}2546#[test]2547fn move_linked_relationship_with_data() {2548#[derive(Component, Clone, PartialEq, Eq, Debug)]2549#[relationship(relationship_target=Target)]2550struct Source {2551#[relationship]2552target: Entity,2553data: Vec<u8>,2554}25552556#[derive(Component, Clone, PartialEq, Eq, Debug)]2557#[relationship_target(relationship=Source, linked_spawn)]2558struct Target {2559#[relationship]2560target: Vec<Entity>,2561data: Vec<u8>,2562}25632564let source_data = alloc::vec![1, 2, 3];2565let target_data = alloc::vec![4, 5, 6];25662567let mut world = World::default();2568let e_target = world.spawn_empty().id();2569let e_source = world2570.spawn(Source {2571target: e_target,2572data: source_data.clone(),2573})2574.id();2575world.get_mut::<Target>(e_target).unwrap().data = target_data.clone();25762577let mut builder = EntityCloner::build_opt_out(&mut world);2578builder.move_components(true).linked_cloning(true);2579let mut cloner = builder.finish();25802581let e_target_moved = world.spawn_empty().id();2582cloner.clone_entity(&mut world, e_target, e_target_moved);25832584assert_eq!(world.get::<Target>(e_target), None);2585assert_eq!(world.get::<Source>(e_source), None);25862587let moved_target = world.get::<Target>(e_target_moved).unwrap();2588assert_eq!(moved_target.data, target_data);2589assert_eq!(moved_target.target.len(), 1);25902591let moved_source = world.get::<Source>(moved_target.target[0]).unwrap();2592assert_eq!(moved_source.data, source_data);2593assert_eq!(moved_source.target, e_target_moved);2594}2595}259625972598