Scheduler lock-up when combining `after` and `chain()`
Bevy version
0.12.1 (-F dynamic_linking)
What you did
Source code (36 lines)
#![allow(clippy::needless_pass_by_value)]
use bevy::prelude::*;
#[derive(Resource)]
pub struct MyTimer(pub Timer);
fn fn_a(time: Res<Time>, mut timer: ResMut<MyTimer>) {
println!("a called");
if timer.0.tick(time.delta()).just_finished() {
println!("a works");
}
}
fn fn_b(mut commands: Commands, timer: ResMut<MyTimer>) {
println!("b called");
if !timer.0.just_finished() {
return;
}
println!("b works");
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(MyTimer(Timer::from_seconds(0.2, TimerMode::Repeating)))
.add_systems(
Update,
(
apply_deferred.after(fn_a), // this line causes a lockup
// fn_a, // uncomment these lines
// apply_deferred, // and it will run properly
fn_b,
)
.chain(),
)
.run();
}
What went wrong
System fn_a is never run (and therefore never frees up the timer for b to perform work - even though b is run)
Can you reproduce this on main?
This should be caught as a warning during schedule initialization, and failing that, should not block indefinitely.
.add_systems(Update, fn_a)
If you add this it should work. The problem here is apply_deferred.after(fn_a) doesn't actually add fn_a to the schedule.
Yeah, but we should fail more gracefully regardless :)
Yeah, but we should fail more gracefully regardless :)
Panic/warn if trying to use .after()/.before() for a system that doesn't exist (or doesn't exist at the end of building the app)?
Yeah, precisely. Ideally we can ensure that hanging is impossible as well, but I'm not sure we can do that cleanly with the current code.