Skip to content

Commit 17e7e8e

Browse files
committed
update archetypes for run criterias
1 parent 9eb1aee commit 17e7e8e

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
@@ -301,11 +301,7 @@ impl ParallelExecutor {
301301

302302
#[cfg(test)]
303303
fn emit_event(&self, event: SchedulingEvent) {
304-
self.events_sender
305-
.as_ref()
306-
.unwrap()
307-
.try_send(event)
308-
.unwrap();
304+
let _ = self.events_sender.as_ref().unwrap().try_send(event);
309305
}
310306
}
311307

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 for RunCriteriaContainer {

crates/bevy_ecs/src/schedule/stage.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,7 @@ impl Stage for SystemStage {
773773
for index in 0..self.run_criteria.len() {
774774
let (run_criteria, tail) = self.run_criteria.split_at_mut(index);
775775
let mut criteria = &mut tail[0];
776+
criteria.update_archetypes(world);
776777
match &mut criteria.inner {
777778
RunCriteriaInner::Single(system) => criteria.should_run = system.run((), world),
778779
RunCriteriaInner::Piped {
@@ -846,6 +847,7 @@ impl Stage for SystemStage {
846847
for index in 0..run_criteria.len() {
847848
let (run_criteria, tail) = run_criteria.split_at_mut(index);
848849
let criteria = &mut tail[0];
850+
criteria.update_archetypes(world);
849851
match criteria.should_run {
850852
ShouldRun::No => (),
851853
ShouldRun::Yes => criteria.should_run = ShouldRun::No,
@@ -2092,4 +2094,77 @@ mod tests {
20922094
);
20932095
}
20942096
}
2097+
2098+
#[test]
2099+
fn run_criteria_with_query() {
2100+
struct Foo;
2101+
2102+
fn even_number_of_entities_critiera(query: Query<&Foo>) -> ShouldRun {
2103+
if query.iter().len() % 2 == 0 {
2104+
ShouldRun::Yes
2105+
} else {
2106+
ShouldRun::No
2107+
}
2108+
}
2109+
2110+
fn spawn_entity(mut commands: crate::prelude::Commands) {
2111+
commands.spawn().insert(Foo);
2112+
}
2113+
2114+
fn count_entities(query: Query<&Foo>, mut res: ResMut<Vec<usize>>) {
2115+
res.push(query.iter().len());
2116+
}
2117+
2118+
let mut world = World::new();
2119+
world.insert_resource(Vec::<usize>::new());
2120+
let mut stage = SystemStage::parallel()
2121+
.with_system(spawn_entity.system().label("spawn"))
2122+
.with_system_set(
2123+
SystemSet::new()
2124+
.with_run_criteria(even_number_of_entities_critiera.system())
2125+
.with_system(count_entities.system().before("spawn")),
2126+
);
2127+
stage.run(&mut world);
2128+
stage.run(&mut world);
2129+
stage.run(&mut world);
2130+
stage.run(&mut world);
2131+
assert_eq!(*world.get_resource::<Vec<usize>>().unwrap(), vec![0, 2]);
2132+
}
2133+
2134+
#[test]
2135+
fn stage_run_criteria_with_query() {
2136+
struct Foo;
2137+
2138+
fn even_number_of_entities_critiera(query: Query<&Foo>) -> ShouldRun {
2139+
if query.iter().len() % 2 == 0 {
2140+
ShouldRun::Yes
2141+
} else {
2142+
ShouldRun::No
2143+
}
2144+
}
2145+
2146+
fn spawn_entity(mut commands: crate::prelude::Commands) {
2147+
commands.spawn().insert(Foo);
2148+
}
2149+
2150+
fn count_entities(query: Query<&Foo>, mut res: ResMut<Vec<usize>>) {
2151+
res.push(query.iter().len());
2152+
}
2153+
2154+
let mut world = World::new();
2155+
world.insert_resource(Vec::<usize>::new());
2156+
let mut stage_spawn = SystemStage::parallel().with_system(spawn_entity.system());
2157+
let mut stage_count = SystemStage::parallel()
2158+
.with_run_criteria(even_number_of_entities_critiera.system())
2159+
.with_system(count_entities.system());
2160+
stage_count.run(&mut world);
2161+
stage_spawn.run(&mut world);
2162+
stage_count.run(&mut world);
2163+
stage_spawn.run(&mut world);
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+
assert_eq!(*world.get_resource::<Vec<usize>>().unwrap(), vec![0, 2]);
2169+
}
20952170
}

0 commit comments

Comments
 (0)