@@ -371,8 +371,19 @@ impl<'w> EntityMut<'w> {
371
371
) {
372
372
let old_archetype = & mut archetypes[ old_archetype_id] ;
373
373
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
374
375
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
+ ) ;
376
387
}
377
388
let old_table_row = remove_result. table_row ;
378
389
let old_table_id = old_archetype. table_id ( ) ;
@@ -395,9 +406,19 @@ impl<'w> EntityMut<'w> {
395
406
// SAFETY: move_result.new_row is a valid position in new_archetype's table
396
407
let new_location = new_archetype. allocate ( entity, move_result. new_row ) ;
397
408
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
399
410
if let Some ( swapped_entity) = move_result. swapped_entity {
400
411
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
+ ) ;
401
422
archetypes[ swapped_location. archetype_id ]
402
423
. set_entity_table_row ( swapped_location. archetype_row , old_table_row) ;
403
424
}
@@ -493,10 +514,19 @@ impl<'w> EntityMut<'w> {
493
514
}
494
515
let remove_result = archetype. swap_remove ( location. archetype_row ) ;
495
516
if let Some ( swapped_entity) = remove_result. swapped_entity {
517
+ let swapped_location = world. entities . get ( swapped_entity) . unwrap ( ) ;
496
518
// SAFETY: swapped_entity is valid and the swapped entity's components are
497
519
// moved to the new location immediately after.
498
520
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
+ ) ;
500
530
}
501
531
}
502
532
table_row = remove_result. table_row ;
@@ -513,6 +543,19 @@ impl<'w> EntityMut<'w> {
513
543
514
544
if let Some ( moved_entity) = moved_entity {
515
545
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
+ }
516
559
world. archetypes [ moved_location. archetype_id ]
517
560
. set_entity_table_row ( moved_location. archetype_row , table_row) ;
518
561
}
@@ -907,4 +950,159 @@ mod tests {
907
950
// Ensure that the location has been properly updated.
908
951
assert ! ( entity. location( ) != old_location) ;
909
952
}
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
+ }
910
1108
}
0 commit comments