@@ -6,8 +6,8 @@ pub use bevy_ecs_macros::Bundle;
66
77use crate :: {
88 archetype:: {
9- Archetype , ArchetypeAfterBundleInsert , ArchetypeId , Archetypes , BundleComponentStatus ,
10- ComponentStatus , SpawnBundleStatus ,
9+ Archetype , ArchetypeAfterBundleInsert , ArchetypeCreated , ArchetypeId , Archetypes ,
10+ BundleComponentStatus , ComponentStatus , SpawnBundleStatus ,
1111 } ,
1212 change_detection:: MaybeLocation ,
1313 component:: {
@@ -732,7 +732,7 @@ impl BundleInfo {
732732 }
733733 }
734734
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 .
736736 /// This could be the same [`ArchetypeId`], in the event that inserting the given bundle
737737 /// does not result in an [`Archetype`] change.
738738 ///
@@ -747,12 +747,12 @@ impl BundleInfo {
747747 components : & Components ,
748748 observers : & Observers ,
749749 archetype_id : ArchetypeId ,
750- ) -> ArchetypeId {
750+ ) -> ( ArchetypeId , bool ) {
751751 if let Some ( archetype_after_insert_id) = archetypes[ archetype_id]
752752 . edges ( )
753753 . get_archetype_after_bundle_insert ( self . id )
754754 {
755- return archetype_after_insert_id;
755+ return ( archetype_after_insert_id, false ) ;
756756 }
757757 let mut new_table_components = Vec :: new ( ) ;
758758 let mut new_sparse_set_components = Vec :: new ( ) ;
@@ -806,7 +806,7 @@ impl BundleInfo {
806806 added,
807807 existing,
808808 ) ;
809- archetype_id
809+ ( archetype_id, false )
810810 } else {
811811 let table_id;
812812 let table_components;
@@ -842,13 +842,14 @@ impl BundleInfo {
842842 } ;
843843 } ;
844844 // 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 (
846846 components,
847847 observers,
848848 table_id,
849849 table_components,
850850 sparse_set_components,
851851 ) ;
852+
852853 // Add an edge from the old archetype to the new archetype.
853854 archetypes[ archetype_id]
854855 . edges_mut ( )
@@ -860,11 +861,11 @@ impl BundleInfo {
860861 added,
861862 existing,
862863 ) ;
863- new_archetype_id
864+ ( new_archetype_id, is_new_created )
864865 }
865866 }
866867
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.
868869 /// (or `None` if the removal was invalid).
869870 /// This could be the same [`ArchetypeId`], in the event that removing the given bundle
870871 /// does not result in an [`Archetype`] change.
@@ -887,7 +888,7 @@ impl BundleInfo {
887888 observers : & Observers ,
888889 archetype_id : ArchetypeId ,
889890 intersection : bool ,
890- ) -> Option < ArchetypeId > {
891+ ) -> ( Option < ArchetypeId > , bool ) {
891892 // Check the archetype graph to see if the bundle has been
892893 // removed from this archetype in the past.
893894 let archetype_after_remove_result = {
@@ -898,9 +899,9 @@ impl BundleInfo {
898899 edges. get_archetype_after_bundle_take ( self . id ( ) )
899900 }
900901 } ;
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 {
902903 // This bundle removal result is cached. Just return that!
903- result
904+ ( result, false )
904905 } else {
905906 let mut next_table_components;
906907 let mut next_sparse_set_components;
@@ -925,7 +926,7 @@ impl BundleInfo {
925926 current_archetype
926927 . edges_mut ( )
927928 . cache_archetype_after_bundle_take ( self . id ( ) , None ) ;
928- return None ;
929+ return ( None , false ) ;
929930 }
930931 }
931932
@@ -953,14 +954,14 @@ impl BundleInfo {
953954 } ;
954955 }
955956
956- let new_archetype_id = archetypes. get_id_or_insert (
957+ let ( new_archetype_id, is_new_created ) = archetypes. get_id_or_insert (
957958 components,
958959 observers,
959960 next_table_id,
960961 next_table_components,
961962 next_sparse_set_components,
962963 ) ;
963- Some ( new_archetype_id)
964+ ( Some ( new_archetype_id) , is_new_created )
964965 } ;
965966 let current_archetype = & mut archetypes[ archetype_id] ;
966967 // Cache the result in an edge.
@@ -973,7 +974,7 @@ impl BundleInfo {
973974 . edges_mut ( )
974975 . cache_archetype_after_bundle_take ( self . id ( ) , result) ;
975976 }
976- result
977+ ( result, is_new_created )
977978 }
978979}
979980
@@ -1036,14 +1037,15 @@ impl<'w> BundleInserter<'w> {
10361037 // SAFETY: We will not make any accesses to the command queue, component or resource data of this world
10371038 let bundle_info = world. bundles . get_unchecked ( bundle_id) ;
10381039 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 (
10401041 & mut world. archetypes ,
10411042 & mut world. storages ,
10421043 & world. components ,
10431044 & world. observers ,
10441045 archetype_id,
10451046 ) ;
1046- if new_archetype_id == archetype_id {
1047+
1048+ let inserter = if new_archetype_id == archetype_id {
10471049 let archetype = & mut world. archetypes [ archetype_id] ;
10481050 // SAFETY: The edge is assured to be initialized when we called insert_bundle_into_archetype
10491051 let archetype_after_insert = unsafe {
@@ -1103,7 +1105,15 @@ impl<'w> BundleInserter<'w> {
11031105 world : world. as_unsafe_world_cell ( ) ,
11041106 }
11051107 }
1108+ } ;
1109+
1110+ if is_new_created {
1111+ inserter
1112+ . world
1113+ . into_deferred ( )
1114+ . trigger ( ArchetypeCreated ( new_archetype_id) ) ;
11061115 }
1116+ inserter
11071117 }
11081118
11091119 /// # Safety
@@ -1421,19 +1431,22 @@ impl<'w> BundleRemover<'w> {
14211431 ) -> Option < Self > {
14221432 let bundle_info = world. bundles . get_unchecked ( bundle_id) ;
14231433 // SAFETY: Caller ensures archetype and bundle ids are correct.
1424- let new_archetype_id = unsafe {
1434+ let ( new_archetype_id, is_new_created ) = unsafe {
14251435 bundle_info. remove_bundle_from_archetype (
14261436 & mut world. archetypes ,
14271437 & mut world. storages ,
14281438 & world. components ,
14291439 & world. observers ,
14301440 archetype_id,
14311441 !require_all,
1432- ) ?
1442+ )
14331443 } ;
1444+ let new_archetype_id = new_archetype_id?;
1445+
14341446 if new_archetype_id == archetype_id {
14351447 return None ;
14361448 }
1449+
14371450 let ( old_archetype, new_archetype) =
14381451 world. archetypes . get_2_mut ( archetype_id, new_archetype_id) ;
14391452
@@ -1447,13 +1460,20 @@ impl<'w> BundleRemover<'w> {
14471460 Some ( ( old. into ( ) , new. into ( ) ) )
14481461 } ;
14491462
1450- Some ( Self {
1463+ let remover = Self {
14511464 bundle_info : bundle_info. into ( ) ,
14521465 new_archetype : new_archetype. into ( ) ,
14531466 old_archetype : old_archetype. into ( ) ,
14541467 old_and_new_table : tables,
14551468 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)
14571477 }
14581478
14591479 /// 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> {
16751695 change_tick : Tick ,
16761696 ) -> Self {
16771697 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 (
16791699 & mut world. archetypes ,
16801700 & mut world. storages ,
16811701 & world. components ,
16821702 & world. observers ,
16831703 ArchetypeId :: EMPTY ,
16841704 ) ;
1705+
16851706 let archetype = & mut world. archetypes [ new_archetype_id] ;
16861707 let table = & mut world. storages . tables [ archetype. table_id ( ) ] ;
1687- Self {
1708+ let spawner = Self {
16881709 bundle_info : bundle_info. into ( ) ,
16891710 table : table. into ( ) ,
16901711 archetype : archetype. into ( ) ,
16911712 change_tick,
16921713 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) ) ;
16931720 }
1721+ spawner
16941722 }
16951723
16961724 #[ inline]
@@ -2043,7 +2071,9 @@ fn sorted_remove<T: Eq + Ord + Copy>(source: &mut Vec<T>, remove: &[T]) {
20432071
20442072#[ cfg( test) ]
20452073mod tests {
2046- use crate :: { component:: HookContext , prelude:: * , world:: DeferredWorld } ;
2074+ use crate :: {
2075+ archetype:: ArchetypeCreated , component:: HookContext , prelude:: * , world:: DeferredWorld ,
2076+ } ;
20472077 use alloc:: vec;
20482078
20492079 #[ derive( Component ) ]
@@ -2280,4 +2310,23 @@ mod tests {
22802310
22812311 assert_eq ! ( a, vec![ 1 ] ) ;
22822312 }
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+ }
22832332}
0 commit comments