Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove extra call to clear_trackers #13762

Merged
merged 10 commits into from
Jun 10, 2024
71 changes: 68 additions & 3 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,11 +916,20 @@ impl Termination for AppExit {

#[cfg(test)]
mod tests {
use std::{marker::PhantomData, mem};
use std::{iter, marker::PhantomData, mem};

use bevy_ecs::{event::EventWriter, schedule::ScheduleLabel, system::Commands};
use bevy_ecs::{
change_detection::{DetectChanges, ResMut},
component::Component,
entity::Entity,
event::EventWriter,
query::With,
removal_detection::RemovedComponents,
schedule::{IntoSystemConfigs, ScheduleLabel},
system::{Commands, Query, Resource},
};

use crate::{App, AppExit, Plugin, Update};
use crate::{App, AppExit, Plugin, SubApp, Update};

struct PluginA;
impl Plugin for PluginA {
Expand Down Expand Up @@ -1123,6 +1132,62 @@ mod tests {
);
}

#[test]
fn test_update_clears_trackers_once() {
#[derive(Component, Copy, Clone)]
struct Foo;

let mut app = App::new();
app.world_mut().spawn_batch(iter::repeat(Foo).take(5));

fn despawn_one_foo(mut commands: Commands, foos: Query<Entity, With<Foo>>) {
if let Some(e) = foos.iter().next() {
commands.entity(e).despawn();
};
}
fn check_despawns(mut removed_foos: RemovedComponents<Foo>) {
let mut despawn_count = 0;
for _ in removed_foos.read() {
despawn_count += 1;
}

assert_eq!(despawn_count, 2);
}

app.add_systems(Update, despawn_one_foo);
app.update(); // Frame 0
app.update(); // Frame 1
app.add_systems(Update, check_despawns.after(despawn_one_foo));
app.update(); // Should see despawns from frames 1 & 2, but not frame 0
}

#[test]
fn test_extract_sees_changes() {
use super::AppLabel;
use crate::{self as bevy_app};

#[derive(AppLabel, Clone, Copy, Hash, PartialEq, Eq, Debug)]
struct MySubApp;

#[derive(Resource)]
struct Foo(usize);

let mut app = App::new();
app.world_mut().insert_resource(Foo(0));
app.add_systems(Update, |mut foo: ResMut<Foo>| {
foo.0 += 1;
});

let mut sub_app = SubApp::new();
sub_app.set_extract(|main_world, _sub_world| {
assert!(main_world.get_resource_ref::<Foo>().unwrap().is_changed());
});

app.insert_sub_app(MySubApp, sub_app);

app.update();
}

#[test]
fn runner_returns_correct_exit_code() {
fn raise_exits(mut exits: EventWriter<AppExit>) {
Expand Down
11 changes: 9 additions & 2 deletions crates/bevy_app/src/sub_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,21 @@ impl SubApp {
}

/// Runs the default schedule.
pub fn update(&mut self) {
///
/// Does not clear internal trackers used for change detection.
pub fn run_default_schedule(&mut self) {
if self.is_building_plugins() {
panic!("SubApp::update() was called while a plugin was building.");
}

if let Some(label) = self.update_schedule {
self.world.run_schedule(label);
}
}

/// Runs the default schedule and updates internal component trackers.
pub fn update(&mut self) {
self.run_default_schedule();
self.world.clear_trackers();
}

Expand Down Expand Up @@ -421,7 +428,7 @@ impl SubApps {
{
#[cfg(feature = "trace")]
let _bevy_frame_update_span = info_span!("main app").entered();
self.main.update();
self.main.run_default_schedule();
}
for (_label, sub_app) in self.sub_apps.iter_mut() {
#[cfg(feature = "trace")]
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_ecs/src/removal_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ impl RemovedComponentEvents {
///
/// If you are using `bevy_ecs` as a standalone crate,
/// note that the `RemovedComponents` list will not be automatically cleared for you,
/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers)
/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers).
///
/// For users of `bevy` and `bevy_app`, this is automatically done in `bevy_app::App::update`.
/// For the main world, [`World::clear_trackers`](World::clear_trackers) is run after the main schedule is run and after
/// `SubApp`'s have run.
/// For users of `bevy` and `bevy_app`, [`World::clear_trackers`](World::clear_trackers) is
/// automatically called by `bevy_app::App::update` and `bevy_app::SubApp::update`.
/// For the main world, this is delayed until after all `SubApp`s have run.
///
/// # Examples
///
Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1113,9 +1113,9 @@ impl World {
/// By clearing this internal state, the world "forgets" about those changes, allowing a new round
/// of detection to be recorded.
///
/// When using `bevy_ecs` as part of the full Bevy engine, this method is added as a system to the
/// main app, to run during `Last`, so you don't need to call it manually. When using `bevy_ecs`
/// as a separate standalone crate however, you need to call this manually.
/// When using `bevy_ecs` as part of the full Bevy engine, this method is called automatically
/// by `bevy_app::App::update` and `bevy_app::SubApp::update`, so you don't need to call it manually.
/// When using `bevy_ecs` as a separate standalone crate however, you do need to call this manually.
///
/// ```
/// # use bevy_ecs::prelude::*;
Expand Down