@@ -6,8 +6,8 @@ pub use bevy_ecs_macros::Bundle;
6
6
7
7
use crate :: {
8
8
archetype:: {
9
- Archetype , ArchetypeAfterBundleInsert , ArchetypeId , Archetypes , BundleComponentStatus ,
10
- ComponentStatus , SpawnBundleStatus ,
9
+ Archetype , ArchetypeAfterBundleInsert , ArchetypeCreated , ArchetypeId , Archetypes ,
10
+ BundleComponentStatus , ComponentStatus , SpawnBundleStatus ,
11
11
} ,
12
12
change_detection:: MaybeLocation ,
13
13
component:: {
@@ -732,7 +732,7 @@ impl BundleInfo {
732
732
}
733
733
}
734
734
735
- /// Inserts a bundle into the given archetype and returns the resulting archetype.
735
+ /// Inserts a bundle into the given archetype and returns the resulting archetype and whether a new archetype was created .
736
736
/// This could be the same [`ArchetypeId`], in the event that inserting the given bundle
737
737
/// does not result in an [`Archetype`] change.
738
738
///
@@ -747,12 +747,12 @@ impl BundleInfo {
747
747
components : & Components ,
748
748
observers : & Observers ,
749
749
archetype_id : ArchetypeId ,
750
- ) -> ArchetypeId {
750
+ ) -> ( ArchetypeId , bool ) {
751
751
if let Some ( archetype_after_insert_id) = archetypes[ archetype_id]
752
752
. edges ( )
753
753
. get_archetype_after_bundle_insert ( self . id )
754
754
{
755
- return archetype_after_insert_id;
755
+ return ( archetype_after_insert_id, false ) ;
756
756
}
757
757
let mut new_table_components = Vec :: new ( ) ;
758
758
let mut new_sparse_set_components = Vec :: new ( ) ;
@@ -806,7 +806,7 @@ impl BundleInfo {
806
806
added,
807
807
existing,
808
808
) ;
809
- archetype_id
809
+ ( archetype_id, false )
810
810
} else {
811
811
let table_id;
812
812
let table_components;
@@ -842,13 +842,14 @@ impl BundleInfo {
842
842
} ;
843
843
} ;
844
844
// SAFETY: ids in self must be valid
845
- let new_archetype_id = archetypes. get_id_or_insert (
845
+ let ( new_archetype_id, is_new_created ) = archetypes. get_id_or_insert (
846
846
components,
847
847
observers,
848
848
table_id,
849
849
table_components,
850
850
sparse_set_components,
851
851
) ;
852
+
852
853
// Add an edge from the old archetype to the new archetype.
853
854
archetypes[ archetype_id]
854
855
. edges_mut ( )
@@ -860,11 +861,11 @@ impl BundleInfo {
860
861
added,
861
862
existing,
862
863
) ;
863
- new_archetype_id
864
+ ( new_archetype_id, is_new_created )
864
865
}
865
866
}
866
867
867
- /// Removes a bundle from the given archetype and returns the resulting archetype
868
+ /// Removes a bundle from the given archetype and returns the resulting archetype and whether a new archetype was created.
868
869
/// (or `None` if the removal was invalid).
869
870
/// This could be the same [`ArchetypeId`], in the event that removing the given bundle
870
871
/// does not result in an [`Archetype`] change.
@@ -887,7 +888,7 @@ impl BundleInfo {
887
888
observers : & Observers ,
888
889
archetype_id : ArchetypeId ,
889
890
intersection : bool ,
890
- ) -> Option < ArchetypeId > {
891
+ ) -> ( Option < ArchetypeId > , bool ) {
891
892
// Check the archetype graph to see if the bundle has been
892
893
// removed from this archetype in the past.
893
894
let archetype_after_remove_result = {
@@ -898,9 +899,9 @@ impl BundleInfo {
898
899
edges. get_archetype_after_bundle_take ( self . id ( ) )
899
900
}
900
901
} ;
901
- let result = if let Some ( result) = archetype_after_remove_result {
902
+ let ( result, is_new_created ) = if let Some ( result) = archetype_after_remove_result {
902
903
// This bundle removal result is cached. Just return that!
903
- result
904
+ ( result, false )
904
905
} else {
905
906
let mut next_table_components;
906
907
let mut next_sparse_set_components;
@@ -925,7 +926,7 @@ impl BundleInfo {
925
926
current_archetype
926
927
. edges_mut ( )
927
928
. cache_archetype_after_bundle_take ( self . id ( ) , None ) ;
928
- return None ;
929
+ return ( None , false ) ;
929
930
}
930
931
}
931
932
@@ -953,14 +954,14 @@ impl BundleInfo {
953
954
} ;
954
955
}
955
956
956
- let new_archetype_id = archetypes. get_id_or_insert (
957
+ let ( new_archetype_id, is_new_created ) = archetypes. get_id_or_insert (
957
958
components,
958
959
observers,
959
960
next_table_id,
960
961
next_table_components,
961
962
next_sparse_set_components,
962
963
) ;
963
- Some ( new_archetype_id)
964
+ ( Some ( new_archetype_id) , is_new_created )
964
965
} ;
965
966
let current_archetype = & mut archetypes[ archetype_id] ;
966
967
// Cache the result in an edge.
@@ -973,7 +974,7 @@ impl BundleInfo {
973
974
. edges_mut ( )
974
975
. cache_archetype_after_bundle_take ( self . id ( ) , result) ;
975
976
}
976
- result
977
+ ( result, is_new_created )
977
978
}
978
979
}
979
980
@@ -1036,14 +1037,15 @@ impl<'w> BundleInserter<'w> {
1036
1037
// SAFETY: We will not make any accesses to the command queue, component or resource data of this world
1037
1038
let bundle_info = world. bundles . get_unchecked ( bundle_id) ;
1038
1039
let bundle_id = bundle_info. id ( ) ;
1039
- let new_archetype_id = bundle_info. insert_bundle_into_archetype (
1040
+ let ( new_archetype_id, is_new_created ) = bundle_info. insert_bundle_into_archetype (
1040
1041
& mut world. archetypes ,
1041
1042
& mut world. storages ,
1042
1043
& world. components ,
1043
1044
& world. observers ,
1044
1045
archetype_id,
1045
1046
) ;
1046
- if new_archetype_id == archetype_id {
1047
+
1048
+ let inserter = if new_archetype_id == archetype_id {
1047
1049
let archetype = & mut world. archetypes [ archetype_id] ;
1048
1050
// SAFETY: The edge is assured to be initialized when we called insert_bundle_into_archetype
1049
1051
let archetype_after_insert = unsafe {
@@ -1103,7 +1105,15 @@ impl<'w> BundleInserter<'w> {
1103
1105
world : world. as_unsafe_world_cell ( ) ,
1104
1106
}
1105
1107
}
1108
+ } ;
1109
+
1110
+ if is_new_created {
1111
+ inserter
1112
+ . world
1113
+ . into_deferred ( )
1114
+ . trigger ( ArchetypeCreated ( new_archetype_id) ) ;
1106
1115
}
1116
+ inserter
1107
1117
}
1108
1118
1109
1119
/// # Safety
@@ -1421,19 +1431,22 @@ impl<'w> BundleRemover<'w> {
1421
1431
) -> Option < Self > {
1422
1432
let bundle_info = world. bundles . get_unchecked ( bundle_id) ;
1423
1433
// SAFETY: Caller ensures archetype and bundle ids are correct.
1424
- let new_archetype_id = unsafe {
1434
+ let ( new_archetype_id, is_new_created ) = unsafe {
1425
1435
bundle_info. remove_bundle_from_archetype (
1426
1436
& mut world. archetypes ,
1427
1437
& mut world. storages ,
1428
1438
& world. components ,
1429
1439
& world. observers ,
1430
1440
archetype_id,
1431
1441
!require_all,
1432
- ) ?
1442
+ )
1433
1443
} ;
1444
+ let new_archetype_id = new_archetype_id?;
1445
+
1434
1446
if new_archetype_id == archetype_id {
1435
1447
return None ;
1436
1448
}
1449
+
1437
1450
let ( old_archetype, new_archetype) =
1438
1451
world. archetypes . get_2_mut ( archetype_id, new_archetype_id) ;
1439
1452
@@ -1447,13 +1460,20 @@ impl<'w> BundleRemover<'w> {
1447
1460
Some ( ( old. into ( ) , new. into ( ) ) )
1448
1461
} ;
1449
1462
1450
- Some ( Self {
1463
+ let remover = Self {
1451
1464
bundle_info : bundle_info. into ( ) ,
1452
1465
new_archetype : new_archetype. into ( ) ,
1453
1466
old_archetype : old_archetype. into ( ) ,
1454
1467
old_and_new_table : tables,
1455
1468
world : world. as_unsafe_world_cell ( ) ,
1456
- } )
1469
+ } ;
1470
+ if is_new_created {
1471
+ remover
1472
+ . world
1473
+ . into_deferred ( )
1474
+ . trigger ( ArchetypeCreated ( new_archetype_id) ) ;
1475
+ }
1476
+ Some ( remover)
1457
1477
}
1458
1478
1459
1479
/// This can be passed to [`remove`](Self::remove) as the `pre_remove` function if you don't want to do anything before removing.
@@ -1675,22 +1695,30 @@ impl<'w> BundleSpawner<'w> {
1675
1695
change_tick : Tick ,
1676
1696
) -> Self {
1677
1697
let bundle_info = world. bundles . get_unchecked ( bundle_id) ;
1678
- let new_archetype_id = bundle_info. insert_bundle_into_archetype (
1698
+ let ( new_archetype_id, is_new_created ) = bundle_info. insert_bundle_into_archetype (
1679
1699
& mut world. archetypes ,
1680
1700
& mut world. storages ,
1681
1701
& world. components ,
1682
1702
& world. observers ,
1683
1703
ArchetypeId :: EMPTY ,
1684
1704
) ;
1705
+
1685
1706
let archetype = & mut world. archetypes [ new_archetype_id] ;
1686
1707
let table = & mut world. storages . tables [ archetype. table_id ( ) ] ;
1687
- Self {
1708
+ let spawner = Self {
1688
1709
bundle_info : bundle_info. into ( ) ,
1689
1710
table : table. into ( ) ,
1690
1711
archetype : archetype. into ( ) ,
1691
1712
change_tick,
1692
1713
world : world. as_unsafe_world_cell ( ) ,
1714
+ } ;
1715
+ if is_new_created {
1716
+ spawner
1717
+ . world
1718
+ . into_deferred ( )
1719
+ . trigger ( ArchetypeCreated ( new_archetype_id) ) ;
1693
1720
}
1721
+ spawner
1694
1722
}
1695
1723
1696
1724
#[ inline]
@@ -2043,7 +2071,9 @@ fn sorted_remove<T: Eq + Ord + Copy>(source: &mut Vec<T>, remove: &[T]) {
2043
2071
2044
2072
#[ cfg( test) ]
2045
2073
mod tests {
2046
- use crate :: { component:: HookContext , prelude:: * , world:: DeferredWorld } ;
2074
+ use crate :: {
2075
+ archetype:: ArchetypeCreated , component:: HookContext , prelude:: * , world:: DeferredWorld ,
2076
+ } ;
2047
2077
use alloc:: vec;
2048
2078
2049
2079
#[ derive( Component ) ]
@@ -2280,4 +2310,23 @@ mod tests {
2280
2310
2281
2311
assert_eq ! ( a, vec![ 1 ] ) ;
2282
2312
}
2313
+
2314
+ #[ test]
2315
+ fn new_archetype_created ( ) {
2316
+ let mut world = World :: new ( ) ;
2317
+ #[ derive( Resource , Default ) ]
2318
+ struct Count ( u32 ) ;
2319
+ world. init_resource :: < Count > ( ) ;
2320
+ world. add_observer ( |_t : Trigger < ArchetypeCreated > , mut count : ResMut < Count > | {
2321
+ count. 0 += 1 ;
2322
+ } ) ;
2323
+
2324
+ let mut e = world. spawn ( ( A , B ) ) ;
2325
+ e. insert ( C ) ;
2326
+ e. remove :: < A > ( ) ;
2327
+ e. insert ( A ) ;
2328
+ e. insert ( A ) ;
2329
+
2330
+ assert_eq ! ( world. resource:: <Count >( ) . 0 , 3 ) ;
2331
+ }
2283
2332
}
0 commit comments