@@ -371,8 +371,19 @@ impl<'w> EntityMut<'w> {
371371 ) {
372372 let old_archetype = & mut archetypes[ old_archetype_id] ;
373373 let remove_result = old_archetype. swap_remove ( old_location. archetype_row ) ;
374+ // if an entity was moved into this entity's archetype row, update its archetype row
374375 if let Some ( swapped_entity) = remove_result. swapped_entity {
375- entities. set ( swapped_entity. index ( ) , old_location) ;
376+ let swapped_location = entities. get ( swapped_entity) . unwrap ( ) ;
377+
378+ entities. set (
379+ swapped_entity. index ( ) ,
380+ EntityLocation {
381+ archetype_id : swapped_location. archetype_id ,
382+ archetype_row : old_location. archetype_row ,
383+ table_id : swapped_location. table_id ,
384+ table_row : swapped_location. table_row ,
385+ } ,
386+ ) ;
376387 }
377388 let old_table_row = remove_result. table_row ;
378389 let old_table_id = old_archetype. table_id ( ) ;
@@ -395,9 +406,19 @@ impl<'w> EntityMut<'w> {
395406 // SAFETY: move_result.new_row is a valid position in new_archetype's table
396407 let new_location = new_archetype. allocate ( entity, move_result. new_row ) ;
397408
398- // if an entity was moved into this entity's table spot , update its table row
409+ // if an entity was moved into this entity's table row , update its table row
399410 if let Some ( swapped_entity) = move_result. swapped_entity {
400411 let swapped_location = entities. get ( swapped_entity) . unwrap ( ) ;
412+
413+ entities. set (
414+ swapped_entity. index ( ) ,
415+ EntityLocation {
416+ archetype_id : swapped_location. archetype_id ,
417+ archetype_row : swapped_location. archetype_row ,
418+ table_id : swapped_location. table_id ,
419+ table_row : old_location. table_row ,
420+ } ,
421+ ) ;
401422 archetypes[ swapped_location. archetype_id ]
402423 . set_entity_table_row ( swapped_location. archetype_row , old_table_row) ;
403424 }
@@ -493,10 +514,19 @@ impl<'w> EntityMut<'w> {
493514 }
494515 let remove_result = archetype. swap_remove ( location. archetype_row ) ;
495516 if let Some ( swapped_entity) = remove_result. swapped_entity {
517+ let swapped_location = world. entities . get ( swapped_entity) . unwrap ( ) ;
496518 // SAFETY: swapped_entity is valid and the swapped entity's components are
497519 // moved to the new location immediately after.
498520 unsafe {
499- world. entities . set ( swapped_entity. index ( ) , location) ;
521+ world. entities . set (
522+ swapped_entity. index ( ) ,
523+ EntityLocation {
524+ archetype_id : swapped_location. archetype_id ,
525+ archetype_row : location. archetype_row ,
526+ table_id : swapped_location. table_id ,
527+ table_row : swapped_location. table_row ,
528+ } ,
529+ ) ;
500530 }
501531 }
502532 table_row = remove_result. table_row ;
@@ -513,6 +543,19 @@ impl<'w> EntityMut<'w> {
513543
514544 if let Some ( moved_entity) = moved_entity {
515545 let moved_location = world. entities . get ( moved_entity) . unwrap ( ) ;
546+ // SAFETY: `moved_entity` is valid and the provided `EntityLocation` accurately reflects
547+ // the current location of the entity and its component data.
548+ unsafe {
549+ world. entities . set (
550+ moved_entity. index ( ) ,
551+ EntityLocation {
552+ archetype_id : moved_location. archetype_id ,
553+ archetype_row : moved_location. archetype_row ,
554+ table_id : moved_location. table_id ,
555+ table_row,
556+ } ,
557+ ) ;
558+ }
516559 world. archetypes [ moved_location. archetype_id ]
517560 . set_entity_table_row ( moved_location. archetype_row , table_row) ;
518561 }
@@ -907,4 +950,159 @@ mod tests {
907950 // Ensure that the location has been properly updated.
908951 assert ! ( entity. location( ) != old_location) ;
909952 }
953+
954+ // regression test for https://github.com/bevyengine/bevy/pull/7805
955+ #[ test]
956+ fn removing_sparse_updates_archetype_row ( ) {
957+ #[ derive( Component , PartialEq , Debug ) ]
958+ struct Dense ( u8 ) ;
959+
960+ #[ derive( Component ) ]
961+ #[ component( storage = "SparseSet" ) ]
962+ struct Sparse ;
963+
964+ let mut world = World :: new ( ) ;
965+ let e1 = world. spawn ( ( Dense ( 0 ) , Sparse ) ) . id ( ) ;
966+ let e2 = world. spawn ( ( Dense ( 1 ) , Sparse ) ) . id ( ) ;
967+
968+ world. entity_mut ( e1) . remove :: < Sparse > ( ) ;
969+ assert_eq ! ( world. entity( e2) . get:: <Dense >( ) . unwrap( ) , & Dense ( 1 ) ) ;
970+ }
971+
972+ // regression test for https://github.com/bevyengine/bevy/pull/7805
973+ #[ test]
974+ fn removing_dense_updates_table_row ( ) {
975+ #[ derive( Component , PartialEq , Debug ) ]
976+ struct Dense ( u8 ) ;
977+
978+ #[ derive( Component ) ]
979+ #[ component( storage = "SparseSet" ) ]
980+ struct Sparse ;
981+
982+ let mut world = World :: new ( ) ;
983+ let e1 = world. spawn ( ( Dense ( 0 ) , Sparse ) ) . id ( ) ;
984+ let e2 = world. spawn ( ( Dense ( 1 ) , Sparse ) ) . id ( ) ;
985+
986+ world. entity_mut ( e1) . remove :: < Dense > ( ) ;
987+ assert_eq ! ( world. entity( e2) . get:: <Dense >( ) . unwrap( ) , & Dense ( 1 ) ) ;
988+ }
989+
990+ // regression test for https://github.com/bevyengine/bevy/pull/7805
991+ #[ test]
992+ fn inserting_sparse_updates_archetype_row ( ) {
993+ #[ derive( Component , PartialEq , Debug ) ]
994+ struct Dense ( u8 ) ;
995+
996+ #[ derive( Component ) ]
997+ #[ component( storage = "SparseSet" ) ]
998+ struct Sparse ;
999+
1000+ let mut world = World :: new ( ) ;
1001+ let e1 = world. spawn ( Dense ( 0 ) ) . id ( ) ;
1002+ let e2 = world. spawn ( Dense ( 1 ) ) . id ( ) ;
1003+
1004+ world. entity_mut ( e1) . insert ( Sparse ) ;
1005+ assert_eq ! ( world. entity( e2) . get:: <Dense >( ) . unwrap( ) , & Dense ( 1 ) ) ;
1006+ }
1007+
1008+ // regression test for https://github.com/bevyengine/bevy/pull/7805
1009+ #[ test]
1010+ fn inserting_dense_updates_archetype_row ( ) {
1011+ #[ derive( Component , PartialEq , Debug ) ]
1012+ struct Dense ( u8 ) ;
1013+
1014+ #[ derive( Component ) ]
1015+ struct Dense2 ;
1016+
1017+ #[ derive( Component ) ]
1018+ #[ component( storage = "SparseSet" ) ]
1019+ struct Sparse ;
1020+
1021+ let mut world = World :: new ( ) ;
1022+ let e1 = world. spawn ( Dense ( 0 ) ) . id ( ) ;
1023+ let e2 = world. spawn ( Dense ( 1 ) ) . id ( ) ;
1024+
1025+ world. entity_mut ( e1) . insert ( Sparse ) . remove :: < Sparse > ( ) ;
1026+
1027+ // archetype with [e2, e1]
1028+ // table with [e1, e2]
1029+
1030+ world. entity_mut ( e2) . insert ( Dense2 ) ;
1031+
1032+ assert_eq ! ( world. entity( e1) . get:: <Dense >( ) . unwrap( ) , & Dense ( 0 ) ) ;
1033+ }
1034+
1035+ #[ test]
1036+ fn inserting_dense_updates_table_row ( ) {
1037+ #[ derive( Component , PartialEq , Debug ) ]
1038+ struct Dense ( u8 ) ;
1039+
1040+ #[ derive( Component ) ]
1041+ struct Dense2 ;
1042+
1043+ #[ derive( Component ) ]
1044+ #[ component( storage = "SparseSet" ) ]
1045+ struct Sparse ;
1046+
1047+ let mut world = World :: new ( ) ;
1048+ let e1 = world. spawn ( Dense ( 0 ) ) . id ( ) ;
1049+ let e2 = world. spawn ( Dense ( 1 ) ) . id ( ) ;
1050+
1051+ world. entity_mut ( e1) . insert ( Sparse ) . remove :: < Sparse > ( ) ;
1052+
1053+ // archetype with [e2, e1]
1054+ // table with [e1, e2]
1055+
1056+ world. entity_mut ( e1) . insert ( Dense2 ) ;
1057+
1058+ assert_eq ! ( world. entity( e2) . get:: <Dense >( ) . unwrap( ) , & Dense ( 1 ) ) ;
1059+ }
1060+
1061+ // regression test for https://github.com/bevyengine/bevy/pull/7805
1062+ #[ test]
1063+ fn despawning_entity_updates_archetype_row ( ) {
1064+ #[ derive( Component , PartialEq , Debug ) ]
1065+ struct Dense ( u8 ) ;
1066+
1067+ #[ derive( Component ) ]
1068+ #[ component( storage = "SparseSet" ) ]
1069+ struct Sparse ;
1070+
1071+ let mut world = World :: new ( ) ;
1072+ let e1 = world. spawn ( Dense ( 0 ) ) . id ( ) ;
1073+ let e2 = world. spawn ( Dense ( 1 ) ) . id ( ) ;
1074+
1075+ world. entity_mut ( e1) . insert ( Sparse ) . remove :: < Sparse > ( ) ;
1076+
1077+ // archetype with [e2, e1]
1078+ // table with [e1, e2]
1079+
1080+ world. entity_mut ( e2) . despawn ( ) ;
1081+
1082+ assert_eq ! ( world. entity( e1) . get:: <Dense >( ) . unwrap( ) , & Dense ( 0 ) ) ;
1083+ }
1084+
1085+ // regression test for https://github.com/bevyengine/bevy/pull/7805
1086+ #[ test]
1087+ fn despawning_entity_updates_table_row ( ) {
1088+ #[ derive( Component , PartialEq , Debug ) ]
1089+ struct Dense ( u8 ) ;
1090+
1091+ #[ derive( Component ) ]
1092+ #[ component( storage = "SparseSet" ) ]
1093+ struct Sparse ;
1094+
1095+ let mut world = World :: new ( ) ;
1096+ let e1 = world. spawn ( Dense ( 0 ) ) . id ( ) ;
1097+ let e2 = world. spawn ( Dense ( 1 ) ) . id ( ) ;
1098+
1099+ world. entity_mut ( e1) . insert ( Sparse ) . remove :: < Sparse > ( ) ;
1100+
1101+ // archetype with [e2, e1]
1102+ // table with [e1, e2]
1103+
1104+ world. entity_mut ( e1) . despawn ( ) ;
1105+
1106+ assert_eq ! ( world. entity( e2) . get:: <Dense >( ) . unwrap( ) , & Dense ( 1 ) ) ;
1107+ }
9101108}
0 commit comments