Skip to content

Commit 74d9040

Browse files
committed
event
1 parent 0ee8bf9 commit 74d9040

File tree

2 files changed

+82
-33
lines changed

2 files changed

+82
-33
lines changed

crates/bevy_ecs/src/archetype.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,23 @@ use crate::{
2323
bundle::BundleId,
2424
component::{ComponentId, Components, RequiredComponentConstructor, StorageType},
2525
entity::{Entity, EntityLocation},
26+
event::Event,
2627
observer::Observers,
2728
storage::{ImmutableSparseSet, SparseArray, SparseSet, TableId, TableRow},
2829
};
2930
use alloc::{boxed::Box, vec::Vec};
30-
use bevy_platform::collections::HashMap;
31+
use bevy_platform::collections::{hash_map::Entry, HashMap};
3132
use core::{
3233
hash::Hash,
3334
ops::{Index, IndexMut, RangeFrom},
3435
};
3536
use nonmax::NonMaxU32;
3637

38+
#[derive(Event)]
39+
#[allow(dead_code)]
40+
41+
pub(crate) struct ArchetypeCreated(pub ArchetypeId);
42+
3743
/// An opaque location within a [`Archetype`].
3844
///
3945
/// This can be used in conjunction with [`ArchetypeId`] to find the exact location
@@ -881,22 +887,21 @@ impl Archetypes {
881887
table_id: TableId,
882888
table_components: Vec<ComponentId>,
883889
sparse_set_components: Vec<ComponentId>,
884-
) -> ArchetypeId {
890+
) -> (ArchetypeId, bool) {
885891
let archetype_identity = ArchetypeComponents {
886892
sparse_set_components: sparse_set_components.into_boxed_slice(),
887893
table_components: table_components.into_boxed_slice(),
888894
};
889895

890896
let archetypes = &mut self.archetypes;
891897
let component_index = &mut self.by_component;
892-
*self
893-
.by_components
894-
.entry(archetype_identity)
895-
.or_insert_with_key(move |identity| {
898+
match self.by_components.entry(archetype_identity) {
899+
Entry::Occupied(occupied) => (*occupied.get(), false),
900+
Entry::Vacant(vacant) => {
896901
let ArchetypeComponents {
897902
table_components,
898903
sparse_set_components,
899-
} = identity;
904+
} = vacant.key();
900905
let id = ArchetypeId::new(archetypes.len());
901906
archetypes.push(Archetype::new(
902907
components,
@@ -907,8 +912,10 @@ impl Archetypes {
907912
table_components.iter().copied(),
908913
sparse_set_components.iter().copied(),
909914
));
910-
id
911-
})
915+
vacant.insert(id);
916+
(id, true)
917+
}
918+
}
912919
}
913920

914921
/// Clears all entities from all archetypes.

crates/bevy_ecs/src/bundle.rs

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ pub use bevy_ecs_macros::Bundle;
66

77
use 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

@@ -1034,15 +1035,21 @@ impl<'w> BundleInserter<'w> {
10341035
change_tick: Tick,
10351036
) -> Self {
10361037
// SAFETY: We will not make any accesses to the command queue, component or resource data of this world
1037-
let bundle_info = world.bundles.get_unchecked(bundle_id);
1038+
let mut 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
);
1047+
1048+
if is_new_created {
1049+
world.trigger(ArchetypeCreated(new_archetype_id));
1050+
bundle_info = world.bundles.get_unchecked(bundle_id);
1051+
}
1052+
10461053
if new_archetype_id == archetype_id {
10471054
let archetype = &mut world.archetypes[archetype_id];
10481055
// SAFETY: The edge is assured to be initialized when we called insert_bundle_into_archetype
@@ -1419,21 +1426,29 @@ impl<'w> BundleRemover<'w> {
14191426
bundle_id: BundleId,
14201427
require_all: bool,
14211428
) -> Option<Self> {
1422-
let bundle_info = world.bundles.get_unchecked(bundle_id);
1429+
let mut bundle_info = world.bundles.get_unchecked(bundle_id);
14231430
// SAFETY: Caller ensures archetype and bundle ids are correct.
1424-
let new_archetype_id = unsafe {
1431+
let (new_archetype_id, is_new_created) = unsafe {
14251432
bundle_info.remove_bundle_from_archetype(
14261433
&mut world.archetypes,
14271434
&mut world.storages,
14281435
&world.components,
14291436
&world.observers,
14301437
archetype_id,
14311438
!require_all,
1432-
)?
1439+
)
14331440
};
1441+
let new_archetype_id = new_archetype_id?;
1442+
14341443
if new_archetype_id == archetype_id {
14351444
return None;
14361445
}
1446+
1447+
if is_new_created {
1448+
world.trigger(ArchetypeCreated(new_archetype_id));
1449+
bundle_info = world.bundles.get_unchecked(bundle_id);
1450+
}
1451+
14371452
let (old_archetype, new_archetype) =
14381453
world.archetypes.get_2_mut(archetype_id, new_archetype_id);
14391454

@@ -1674,14 +1689,20 @@ impl<'w> BundleSpawner<'w> {
16741689
bundle_id: BundleId,
16751690
change_tick: Tick,
16761691
) -> Self {
1677-
let bundle_info = world.bundles.get_unchecked(bundle_id);
1678-
let new_archetype_id = bundle_info.insert_bundle_into_archetype(
1692+
let mut bundle_info = world.bundles.get_unchecked(bundle_id);
1693+
let (new_archetype_id, is_new_created) = bundle_info.insert_bundle_into_archetype(
16791694
&mut world.archetypes,
16801695
&mut world.storages,
16811696
&world.components,
16821697
&world.observers,
16831698
ArchetypeId::EMPTY,
16841699
);
1700+
1701+
if is_new_created {
1702+
world.trigger(ArchetypeCreated(new_archetype_id));
1703+
bundle_info = world.bundles.get_unchecked(bundle_id);
1704+
}
1705+
16851706
let archetype = &mut world.archetypes[new_archetype_id];
16861707
let table = &mut world.storages.tables[archetype.table_id()];
16871708
Self {
@@ -2043,7 +2064,9 @@ fn sorted_remove<T: Eq + Ord + Copy>(source: &mut Vec<T>, remove: &[T]) {
20432064

20442065
#[cfg(test)]
20452066
mod tests {
2046-
use crate::{component::HookContext, prelude::*, world::DeferredWorld};
2067+
use crate::{
2068+
archetype::ArchetypeCreated, component::HookContext, prelude::*, world::DeferredWorld,
2069+
};
20472070
use alloc::vec;
20482071

20492072
#[derive(Component)]
@@ -2280,4 +2303,23 @@ mod tests {
22802303

22812304
assert_eq!(a, vec![1]);
22822305
}
2306+
2307+
#[test]
2308+
fn new_archetype_creadted() {
2309+
let mut world = World::new();
2310+
#[derive(Resource, Default)]
2311+
struct Count(u32);
2312+
world.init_resource::<Count>();
2313+
world.add_observer(|_t: Trigger<ArchetypeCreated>, mut count: ResMut<Count>| {
2314+
count.0 += 1;
2315+
});
2316+
2317+
let mut e = world.spawn((A, B));
2318+
e.insert(C);
2319+
e.remove::<A>();
2320+
e.insert(A);
2321+
e.insert(A);
2322+
2323+
assert_eq!(world.resource::<Count>().0, 3);
2324+
}
22832325
}

0 commit comments

Comments
 (0)