Skip to content

Commit 053f4ae

Browse files
committed
update archetypes for run criterias
1 parent 883abbb commit 053f4ae

File tree

3 files changed

+124
-6
lines changed

3 files changed

+124
-6
lines changed

crates/bevy_ecs/src/schedule/executor_parallel.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -311,11 +311,7 @@ impl ParallelExecutor {
311311

312312
#[cfg(test)]
313313
fn emit_event(&self, event: SchedulingEvent) {
314-
self.events_sender
315-
.as_ref()
316-
.unwrap()
317-
.try_send(event)
318-
.unwrap();
314+
let _ = self.events_sender.as_ref().unwrap().try_send(event);
319315
}
320316
}
321317

crates/bevy_ecs/src/schedule/run_criteria.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
archetype::{Archetype, ArchetypeComponentId},
2+
archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration},
33
component::ComponentId,
44
query::Access,
55
schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel},
@@ -47,13 +47,16 @@ pub enum ShouldRun {
4747
pub(crate) struct BoxedRunCriteria {
4848
criteria_system: Option<BoxedSystem<(), ShouldRun>>,
4949
initialized: bool,
50+
archetype_generation: ArchetypeGeneration,
5051
}
5152

5253
impl Default for BoxedRunCriteria {
5354
fn default() -> Self {
5455
Self {
5556
criteria_system: None,
5657
initialized: false,
58+
// MAX ensures access information will be initialized on first run.
59+
archetype_generation: ArchetypeGeneration::new(usize::MAX),
5760
}
5861
}
5962
}
@@ -70,6 +73,21 @@ impl BoxedRunCriteria {
7073
run_criteria.initialize(world);
7174
self.initialized = true;
7275
}
76+
let archetypes = world.archetypes();
77+
let old_generation = self.archetype_generation;
78+
let new_generation = archetypes.generation();
79+
if old_generation != new_generation {
80+
let archetype_index_range = if old_generation.value() == usize::MAX {
81+
0..archetypes.len()
82+
} else {
83+
old_generation.value()..archetypes.len()
84+
};
85+
for archetype in archetypes.archetypes[archetype_index_range].iter() {
86+
run_criteria.new_archetype(archetype);
87+
}
88+
89+
self.archetype_generation = new_generation;
90+
}
7391
let should_run = run_criteria.run((), world);
7492
run_criteria.apply_buffers(world);
7593
should_run
@@ -93,6 +111,7 @@ pub(crate) struct RunCriteriaContainer {
93111
pub label: Option<BoxedRunCriteriaLabel>,
94112
pub before: Vec<BoxedRunCriteriaLabel>,
95113
pub after: Vec<BoxedRunCriteriaLabel>,
114+
archetype_generation: ArchetypeGeneration,
96115
}
97116

98117
impl RunCriteriaContainer {
@@ -106,6 +125,8 @@ impl RunCriteriaContainer {
106125
label: descriptor.label,
107126
before: descriptor.before,
108127
after: descriptor.after,
128+
// MAX ensures access information will be initialized on first run.
129+
archetype_generation: ArchetypeGeneration::new(usize::MAX),
109130
}
110131
}
111132

@@ -122,6 +143,32 @@ impl RunCriteriaContainer {
122143
RunCriteriaInner::Piped { system, .. } => system.initialize(world),
123144
}
124145
}
146+
147+
pub fn update_archetypes(&mut self, world: &World) {
148+
let archetypes = world.archetypes();
149+
let old_generation = self.archetype_generation;
150+
let new_generation = archetypes.generation();
151+
if old_generation == new_generation {
152+
return;
153+
}
154+
let archetype_index_range = if old_generation.value() == usize::MAX {
155+
0..archetypes.len()
156+
} else {
157+
old_generation.value()..archetypes.len()
158+
};
159+
for archetype in archetypes.archetypes[archetype_index_range].iter() {
160+
match &mut self.inner {
161+
RunCriteriaInner::Single(system) => {
162+
system.new_archetype(archetype);
163+
}
164+
165+
RunCriteriaInner::Piped { system, .. } => {
166+
system.new_archetype(archetype);
167+
}
168+
}
169+
}
170+
self.archetype_generation = new_generation;
171+
}
125172
}
126173

127174
impl GraphNode<BoxedRunCriteriaLabel> for RunCriteriaContainer {

crates/bevy_ecs/src/schedule/stage.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,7 @@ impl Stage for SystemStage {
777777
for index in 0..self.run_criteria.len() {
778778
let (run_criteria, tail) = self.run_criteria.split_at_mut(index);
779779
let mut criteria = &mut tail[0];
780+
criteria.update_archetypes(world);
780781
match &mut criteria.inner {
781782
RunCriteriaInner::Single(system) => criteria.should_run = system.run((), world),
782783
RunCriteriaInner::Piped {
@@ -850,6 +851,7 @@ impl Stage for SystemStage {
850851
for index in 0..run_criteria.len() {
851852
let (run_criteria, tail) = run_criteria.split_at_mut(index);
852853
let criteria = &mut tail[0];
854+
criteria.update_archetypes(world);
853855
match criteria.should_run {
854856
ShouldRun::No => (),
855857
ShouldRun::Yes => criteria.should_run = ShouldRun::No,
@@ -2096,4 +2098,77 @@ mod tests {
20962098
);
20972099
}
20982100
}
2101+
2102+
#[test]
2103+
fn run_criteria_with_query() {
2104+
struct Foo;
2105+
2106+
fn even_number_of_entities_critiera(query: Query<&Foo>) -> ShouldRun {
2107+
if query.iter().len() % 2 == 0 {
2108+
ShouldRun::Yes
2109+
} else {
2110+
ShouldRun::No
2111+
}
2112+
}
2113+
2114+
fn spawn_entity(mut commands: crate::prelude::Commands) {
2115+
commands.spawn().insert(Foo);
2116+
}
2117+
2118+
fn count_entities(query: Query<&Foo>, mut res: ResMut<Vec<usize>>) {
2119+
res.push(query.iter().len());
2120+
}
2121+
2122+
let mut world = World::new();
2123+
world.insert_resource(Vec::<usize>::new());
2124+
let mut stage = SystemStage::parallel()
2125+
.with_system(spawn_entity.system().label("spawn"))
2126+
.with_system_set(
2127+
SystemSet::new()
2128+
.with_run_criteria(even_number_of_entities_critiera.system())
2129+
.with_system(count_entities.system().before("spawn")),
2130+
);
2131+
stage.run(&mut world);
2132+
stage.run(&mut world);
2133+
stage.run(&mut world);
2134+
stage.run(&mut world);
2135+
assert_eq!(*world.get_resource::<Vec<usize>>().unwrap(), vec![0, 2]);
2136+
}
2137+
2138+
#[test]
2139+
fn stage_run_criteria_with_query() {
2140+
struct Foo;
2141+
2142+
fn even_number_of_entities_critiera(query: Query<&Foo>) -> ShouldRun {
2143+
if query.iter().len() % 2 == 0 {
2144+
ShouldRun::Yes
2145+
} else {
2146+
ShouldRun::No
2147+
}
2148+
}
2149+
2150+
fn spawn_entity(mut commands: crate::prelude::Commands) {
2151+
commands.spawn().insert(Foo);
2152+
}
2153+
2154+
fn count_entities(query: Query<&Foo>, mut res: ResMut<Vec<usize>>) {
2155+
res.push(query.iter().len());
2156+
}
2157+
2158+
let mut world = World::new();
2159+
world.insert_resource(Vec::<usize>::new());
2160+
let mut stage_spawn = SystemStage::parallel().with_system(spawn_entity.system());
2161+
let mut stage_count = SystemStage::parallel()
2162+
.with_run_criteria(even_number_of_entities_critiera.system())
2163+
.with_system(count_entities.system());
2164+
stage_count.run(&mut world);
2165+
stage_spawn.run(&mut world);
2166+
stage_count.run(&mut world);
2167+
stage_spawn.run(&mut world);
2168+
stage_count.run(&mut world);
2169+
stage_spawn.run(&mut world);
2170+
stage_count.run(&mut world);
2171+
stage_spawn.run(&mut world);
2172+
assert_eq!(*world.get_resource::<Vec<usize>>().unwrap(), vec![0, 2]);
2173+
}
20992174
}

0 commit comments

Comments
 (0)