@@ -5,6 +5,7 @@ use bumpalo::Bump;
5
5
use core:: any:: TypeId ;
6
6
7
7
use crate :: {
8
+ archetype:: Archetype ,
8
9
bundle:: Bundle ,
9
10
component:: { Component , ComponentCloneBehavior , ComponentCloneFn , ComponentId , ComponentInfo } ,
10
11
entity:: { hash_map:: EntityHashMap , Entities , Entity , EntityMapper } ,
@@ -346,6 +347,7 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
346
347
pub struct EntityCloner {
347
348
filter_allows_components : bool ,
348
349
filter : HashSet < ComponentId > ,
350
+ filter_required : HashSet < ComponentId > ,
349
351
clone_behavior_overrides : HashMap < ComponentId , ComponentCloneBehavior > ,
350
352
move_components : bool ,
351
353
linked_cloning : bool ,
@@ -362,6 +364,7 @@ impl Default for EntityCloner {
362
364
linked_cloning : false ,
363
365
default_clone_fn : ComponentCloneBehavior :: global_default_fn ( ) ,
364
366
filter : Default :: default ( ) ,
367
+ filter_required : Default :: default ( ) ,
365
368
clone_behavior_overrides : Default :: default ( ) ,
366
369
clone_queue : Default :: default ( ) ,
367
370
deferred_commands : Default :: default ( ) ,
@@ -465,6 +468,12 @@ impl EntityCloner {
465
468
{
466
469
let world = world. as_unsafe_world_cell ( ) ;
467
470
let source_entity = world. get_entity ( source) . expect ( "Source entity must exist" ) ;
471
+ let target_archetype = ( !self . filter_required . is_empty ( ) ) . then ( || {
472
+ world
473
+ . get_entity ( target)
474
+ . expect ( "Target entity must exist" )
475
+ . archetype ( )
476
+ } ) ;
468
477
469
478
#[ cfg( feature = "bevy_reflect" ) ]
470
479
// SAFETY: we have unique access to `world`, nothing else accesses the registry at this moment, and we clone
@@ -481,7 +490,7 @@ impl EntityCloner {
481
490
bundle_scratch = BundleScratch :: with_capacity ( archetype. component_count ( ) ) ;
482
491
483
492
for component in archetype. components ( ) {
484
- if !self . is_cloning_allowed ( & component) {
493
+ if !self . is_cloning_allowed ( & component, target_archetype ) {
485
494
continue ;
486
495
}
487
496
@@ -605,9 +614,19 @@ impl EntityCloner {
605
614
target
606
615
}
607
616
608
- fn is_cloning_allowed ( & self , component : & ComponentId ) -> bool {
609
- ( self . filter_allows_components && self . filter . contains ( component) )
610
- || ( !self . filter_allows_components && !self . filter . contains ( component) )
617
+ fn is_cloning_allowed (
618
+ & self ,
619
+ component : & ComponentId ,
620
+ target_archetype : Option < & Archetype > ,
621
+ ) -> bool {
622
+ if self . filter_allows_components {
623
+ self . filter . contains ( component)
624
+ || target_archetype. is_some_and ( |archetype| {
625
+ !archetype. contains ( * component) && self . filter_required . contains ( component)
626
+ } )
627
+ } else {
628
+ !self . filter . contains ( component) && !self . filter_required . contains ( component)
629
+ }
611
630
}
612
631
}
613
632
@@ -809,9 +828,9 @@ impl<'w> EntityClonerBuilder<'w> {
809
828
if let Some ( info) = self . world . components ( ) . get_info ( id) {
810
829
for required_id in info. required_components ( ) . iter_ids ( ) {
811
830
if self . entity_cloner . filter_allows_components {
812
- self . entity_cloner . filter . insert ( required_id) ;
831
+ self . entity_cloner . filter_required . insert ( required_id) ;
813
832
} else {
814
- self . entity_cloner . filter . remove ( & required_id) ;
833
+ self . entity_cloner . filter_required . remove ( & required_id) ;
815
834
}
816
835
}
817
836
}
@@ -829,9 +848,9 @@ impl<'w> EntityClonerBuilder<'w> {
829
848
if let Some ( info) = self . world . components ( ) . get_info ( id) {
830
849
for required_id in info. required_components ( ) . iter_ids ( ) {
831
850
if self . entity_cloner . filter_allows_components {
832
- self . entity_cloner . filter . remove ( & required_id) ;
851
+ self . entity_cloner . filter_required . remove ( & required_id) ;
833
852
} else {
834
- self . entity_cloner . filter . insert ( required_id) ;
853
+ self . entity_cloner . filter_required . insert ( required_id) ;
835
854
}
836
855
}
837
856
}
@@ -1406,4 +1425,36 @@ mod tests {
1406
1425
) ;
1407
1426
assert ! ( world. resource:: <FromWorldCalled >( ) . 0 ) ;
1408
1427
}
1428
+
1429
+ #[ test]
1430
+ fn cloning_with_required_components_preserves_existing ( ) {
1431
+ #[ derive( Component , Clone , PartialEq , Debug , Default ) ]
1432
+ #[ require( B ( 5 ) ) ]
1433
+ struct A ;
1434
+
1435
+ #[ derive( Component , Clone , PartialEq , Debug ) ]
1436
+ struct B ( u32 ) ;
1437
+
1438
+ let mut world = World :: default ( ) ;
1439
+
1440
+ let e = world. spawn ( ( A , B ( 0 ) ) ) . id ( ) ;
1441
+ let e_clone = world. spawn ( B ( 1 ) ) . id ( ) ;
1442
+
1443
+ EntityCloner :: build ( & mut world)
1444
+ . deny_all ( )
1445
+ . allow :: < A > ( )
1446
+ . clone_entity ( e, e_clone) ;
1447
+
1448
+ assert_eq ! ( world. entity( e_clone) . get:: <A >( ) , Some ( & A ) ) ;
1449
+ assert_eq ! ( world. entity( e_clone) . get:: <B >( ) , Some ( & B ( 1 ) ) ) ;
1450
+
1451
+ let e_clone2 = world. spawn ( B ( 2 ) ) . id ( ) ;
1452
+
1453
+ EntityCloner :: build ( & mut world)
1454
+ . allow_all ( )
1455
+ . deny :: < A > ( )
1456
+ . clone_entity ( e, e_clone2) ;
1457
+
1458
+ assert_eq ! ( world. entity( e_clone2) . get:: <B >( ) , Some ( & B ( 2 ) ) ) ;
1459
+ }
1409
1460
}
0 commit comments