mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 06:00:20 +00:00
Schedule-First: the new and improved add_systems (#8079)
Co-authored-by: Mike <mike.hsu@gmail.com>
This commit is contained in:
parent
bca4b36d4d
commit
aefe1f0739
258 changed files with 2177 additions and 2798 deletions
|
@ -9,7 +9,7 @@ fn setup(system_count: usize) -> (World, Schedule) {
|
||||||
fn empty() {}
|
fn empty() {}
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
for _ in 0..system_count {
|
for _ in 0..system_count {
|
||||||
schedule.add_system(empty);
|
schedule.add_systems(empty);
|
||||||
}
|
}
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
(world, schedule)
|
(world, schedule)
|
||||||
|
|
|
@ -154,7 +154,7 @@ fn empty_archetypes(criterion: &mut Criterion) {
|
||||||
let mut group = criterion.benchmark_group("empty_archetypes");
|
let mut group = criterion.benchmark_group("empty_archetypes");
|
||||||
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
||||||
let (mut world, mut schedule) = setup(true, |schedule| {
|
let (mut world, mut schedule) = setup(true, |schedule| {
|
||||||
schedule.add_system(iter);
|
schedule.add_systems(iter);
|
||||||
});
|
});
|
||||||
add_archetypes(&mut world, archetype_count);
|
add_archetypes(&mut world, archetype_count);
|
||||||
world.clear_entities();
|
world.clear_entities();
|
||||||
|
@ -185,7 +185,7 @@ fn empty_archetypes(criterion: &mut Criterion) {
|
||||||
}
|
}
|
||||||
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
||||||
let (mut world, mut schedule) = setup(true, |schedule| {
|
let (mut world, mut schedule) = setup(true, |schedule| {
|
||||||
schedule.add_system(for_each);
|
schedule.add_systems(for_each);
|
||||||
});
|
});
|
||||||
add_archetypes(&mut world, archetype_count);
|
add_archetypes(&mut world, archetype_count);
|
||||||
world.clear_entities();
|
world.clear_entities();
|
||||||
|
@ -216,7 +216,7 @@ fn empty_archetypes(criterion: &mut Criterion) {
|
||||||
}
|
}
|
||||||
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
||||||
let (mut world, mut schedule) = setup(true, |schedule| {
|
let (mut world, mut schedule) = setup(true, |schedule| {
|
||||||
schedule.add_system(par_for_each);
|
schedule.add_systems(par_for_each);
|
||||||
});
|
});
|
||||||
add_archetypes(&mut world, archetype_count);
|
add_archetypes(&mut world, archetype_count);
|
||||||
world.clear_entities();
|
world.clear_entities();
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn run_condition_yes(criterion: &mut Criterion) {
|
||||||
fn empty() {}
|
fn empty() {}
|
||||||
for amount in 0..21 {
|
for amount in 0..21 {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
schedule.add_system(empty.run_if(yes));
|
schedule.add_systems(empty.run_if(yes));
|
||||||
for _ in 0..amount {
|
for _ in 0..amount {
|
||||||
schedule.add_systems((empty, empty, empty, empty, empty).distributive_run_if(yes));
|
schedule.add_systems((empty, empty, empty, empty, empty).distributive_run_if(yes));
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ pub fn run_condition_no(criterion: &mut Criterion) {
|
||||||
fn empty() {}
|
fn empty() {}
|
||||||
for amount in 0..21 {
|
for amount in 0..21 {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
schedule.add_system(empty.run_if(no));
|
schedule.add_systems(empty.run_if(no));
|
||||||
for _ in 0..amount {
|
for _ in 0..amount {
|
||||||
schedule.add_systems((empty, empty, empty, empty, empty).distributive_run_if(no));
|
schedule.add_systems((empty, empty, empty, empty, empty).distributive_run_if(no));
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ pub fn run_condition_yes_with_query(criterion: &mut Criterion) {
|
||||||
}
|
}
|
||||||
for amount in 0..21 {
|
for amount in 0..21 {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
schedule.add_system(empty.run_if(yes_with_query));
|
schedule.add_systems(empty.run_if(yes_with_query));
|
||||||
for _ in 0..amount {
|
for _ in 0..amount {
|
||||||
schedule.add_systems(
|
schedule.add_systems(
|
||||||
(empty, empty, empty, empty, empty).distributive_run_if(yes_with_query),
|
(empty, empty, empty, empty, empty).distributive_run_if(yes_with_query),
|
||||||
|
@ -101,7 +101,7 @@ pub fn run_condition_yes_with_resource(criterion: &mut Criterion) {
|
||||||
}
|
}
|
||||||
for amount in 0..21 {
|
for amount in 0..21 {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
schedule.add_system(empty.run_if(yes_with_resource));
|
schedule.add_systems(empty.run_if(yes_with_resource));
|
||||||
for _ in 0..amount {
|
for _ in 0..amount {
|
||||||
schedule.add_systems(
|
schedule.add_systems(
|
||||||
(empty, empty, empty, empty, empty).distributive_run_if(yes_with_resource),
|
(empty, empty, empty, empty, empty).distributive_run_if(yes_with_resource),
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub fn empty_systems(criterion: &mut Criterion) {
|
||||||
for amount in 0..5 {
|
for amount in 0..5 {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
for _ in 0..amount {
|
for _ in 0..amount {
|
||||||
schedule.add_system(empty);
|
schedule.add_systems(empty);
|
||||||
}
|
}
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
group.bench_function(&format!("{:03}_systems", amount), |bencher| {
|
group.bench_function(&format!("{:03}_systems", amount), |bencher| {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy_app::App;
|
use bevy_app::{App, Update};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use criterion::Criterion;
|
use criterion::Criterion;
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ pub fn build_schedule(criterion: &mut Criterion) {
|
||||||
group.measurement_time(std::time::Duration::from_secs(15));
|
group.measurement_time(std::time::Duration::from_secs(15));
|
||||||
|
|
||||||
// Method: generate a set of `graph_size` systems which have a One True Ordering.
|
// Method: generate a set of `graph_size` systems which have a One True Ordering.
|
||||||
// Add system to the schedule with full constraints. Hopefully this should be maximimally
|
// Add system to the schedule with full constraints. Hopefully this should be maximally
|
||||||
// difficult for bevy to figure out.
|
// difficult for bevy to figure out.
|
||||||
let labels: Vec<_> = (0..1000).map(|i| NumSet(i)).collect();
|
let labels: Vec<_> = (0..1000).map(|i| NumSet(i)).collect();
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ pub fn build_schedule(criterion: &mut Criterion) {
|
||||||
bencher.iter(|| {
|
bencher.iter(|| {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
for _ in 0..graph_size {
|
for _ in 0..graph_size {
|
||||||
app.add_system(empty_system);
|
app.add_systems(Update, empty_system);
|
||||||
}
|
}
|
||||||
app.update();
|
app.update();
|
||||||
});
|
});
|
||||||
|
@ -93,7 +93,7 @@ pub fn build_schedule(criterion: &mut Criterion) {
|
||||||
group.bench_function(format!("{graph_size}_schedule"), |bencher| {
|
group.bench_function(format!("{graph_size}_schedule"), |bencher| {
|
||||||
bencher.iter(|| {
|
bencher.iter(|| {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_system(empty_system.in_set(DummySet));
|
app.add_systems(Update, empty_system.in_set(DummySet));
|
||||||
|
|
||||||
// Build a fully-connected dependency graph describing the One True Ordering.
|
// Build a fully-connected dependency graph describing the One True Ordering.
|
||||||
// Not particularly realistic but this can be refined later.
|
// Not particularly realistic but this can be refined later.
|
||||||
|
@ -105,7 +105,7 @@ pub fn build_schedule(criterion: &mut Criterion) {
|
||||||
for label in &labels[i + 1..graph_size] {
|
for label in &labels[i + 1..graph_size] {
|
||||||
sys = sys.before(*label);
|
sys = sys.before(*label);
|
||||||
}
|
}
|
||||||
app.add_system(sys);
|
app.add_systems(Update, sys);
|
||||||
}
|
}
|
||||||
// Run the app for a single frame.
|
// Run the app for a single frame.
|
||||||
// This is necessary since dependency resolution does not occur until the game runs.
|
// This is necessary since dependency resolution does not occur until the game runs.
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use bevy_app::{App, CoreSet, Plugin};
|
use bevy_app::{App, Plugin, PostUpdate};
|
||||||
use bevy_asset::{AddAsset, Assets, Handle};
|
use bevy_asset::{AddAsset, Assets, Handle};
|
||||||
use bevy_core::Name;
|
use bevy_core::Name;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -550,10 +550,9 @@ impl Plugin for AnimationPlugin {
|
||||||
app.add_asset::<AnimationClip>()
|
app.add_asset::<AnimationClip>()
|
||||||
.register_asset_reflect::<AnimationClip>()
|
.register_asset_reflect::<AnimationClip>()
|
||||||
.register_type::<AnimationPlayer>()
|
.register_type::<AnimationPlayer>()
|
||||||
.add_system(
|
.add_systems(
|
||||||
animation_player
|
PostUpdate,
|
||||||
.in_base_set(CoreSet::PostUpdate)
|
animation_player.before(TransformSystem::TransformPropagate),
|
||||||
.before(TransformSystem::TransformPropagate),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
CoreSchedule, CoreSet, IntoSystemAppConfig, IntoSystemAppConfigs, Plugin, PluginGroup,
|
First, Main, MainSchedulePlugin, Plugin, PluginGroup, Startup, StateTransition, Update,
|
||||||
StartupSet, SystemAppConfig,
|
|
||||||
};
|
};
|
||||||
pub use bevy_derive::AppLabel;
|
pub use bevy_derive::AppLabel;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
schedule::{
|
schedule::{
|
||||||
apply_state_transition, common_conditions::run_once as run_once_condition,
|
apply_state_transition, common_conditions::run_once as run_once_condition,
|
||||||
run_enter_schedule, BoxedScheduleLabel, IntoSystemConfig, IntoSystemSetConfigs,
|
run_enter_schedule, BoxedScheduleLabel, IntoSystemConfigs, IntoSystemSetConfigs,
|
||||||
ScheduleLabel,
|
ScheduleLabel,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -53,7 +52,7 @@ pub(crate) enum AppError {
|
||||||
/// #
|
/// #
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .add_system(hello_world_system)
|
/// .add_systems(Update, hello_world_system)
|
||||||
/// .run();
|
/// .run();
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
@ -74,12 +73,10 @@ pub struct App {
|
||||||
pub runner: Box<dyn Fn(App) + Send>, // Send bound is required to make App Send
|
pub runner: Box<dyn Fn(App) + Send>, // Send bound is required to make App Send
|
||||||
/// The schedule that systems are added to by default.
|
/// The schedule that systems are added to by default.
|
||||||
///
|
///
|
||||||
/// This is initially set to [`CoreSchedule::Main`].
|
/// The schedule that runs the main loop of schedule execution.
|
||||||
pub default_schedule_label: BoxedScheduleLabel,
|
|
||||||
/// The schedule that controls the outer loop of schedule execution.
|
|
||||||
///
|
///
|
||||||
/// This is initially set to [`CoreSchedule::Outer`].
|
/// This is initially set to [`Main`].
|
||||||
pub outer_schedule_label: BoxedScheduleLabel,
|
pub main_schedule_label: BoxedScheduleLabel,
|
||||||
sub_apps: HashMap<AppLabelId, SubApp>,
|
sub_apps: HashMap<AppLabelId, SubApp>,
|
||||||
plugin_registry: Vec<Box<dyn Plugin>>,
|
plugin_registry: Vec<Box<dyn Plugin>>,
|
||||||
plugin_name_added: HashSet<String>,
|
plugin_name_added: HashSet<String>,
|
||||||
|
@ -104,7 +101,7 @@ impl Debug for App {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use bevy_app::{App, AppLabel, SubApp, CoreSchedule};
|
/// # use bevy_app::{App, AppLabel, SubApp, Main};
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::schedule::ScheduleLabel;
|
/// # use bevy_ecs::schedule::ScheduleLabel;
|
||||||
///
|
///
|
||||||
|
@ -122,12 +119,10 @@ impl Debug for App {
|
||||||
/// // create a app with a resource and a single schedule
|
/// // create a app with a resource and a single schedule
|
||||||
/// let mut sub_app = App::empty();
|
/// let mut sub_app = App::empty();
|
||||||
/// // add an outer schedule that runs the main schedule
|
/// // add an outer schedule that runs the main schedule
|
||||||
/// sub_app.add_simple_outer_schedule();
|
|
||||||
/// sub_app.insert_resource(Val(100));
|
/// sub_app.insert_resource(Val(100));
|
||||||
///
|
///
|
||||||
/// // initialize main schedule
|
/// // initialize main schedule
|
||||||
/// sub_app.init_schedule(CoreSchedule::Main);
|
/// sub_app.add_systems(Main, |counter: Res<Val>| {
|
||||||
/// sub_app.add_system(|counter: Res<Val>| {
|
|
||||||
/// // since we assigned the value from the main world in extract
|
/// // since we assigned the value from the main world in extract
|
||||||
/// // we see that value instead of 100
|
/// // we see that value instead of 100
|
||||||
/// assert_eq!(counter.0, 10);
|
/// assert_eq!(counter.0, 10);
|
||||||
|
@ -169,7 +164,7 @@ impl SubApp {
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
self.app
|
self.app
|
||||||
.world
|
.world
|
||||||
.run_schedule_ref(&*self.app.outer_schedule_label);
|
.run_schedule_ref(&*self.app.main_schedule_label);
|
||||||
self.app.world.clear_trackers();
|
self.app.world.clear_trackers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +190,7 @@ impl Default for App {
|
||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
app.init_resource::<AppTypeRegistry>();
|
app.init_resource::<AppTypeRegistry>();
|
||||||
|
|
||||||
app.add_default_schedules();
|
app.add_plugin(MainSchedulePlugin);
|
||||||
|
|
||||||
app.add_event::<AppExit>();
|
app.add_event::<AppExit>();
|
||||||
|
|
||||||
#[cfg(feature = "bevy_ci_testing")]
|
#[cfg(feature = "bevy_ci_testing")]
|
||||||
|
@ -211,8 +205,6 @@ impl Default for App {
|
||||||
impl App {
|
impl App {
|
||||||
/// Creates a new [`App`] with some default structure to enable core engine features.
|
/// Creates a new [`App`] with some default structure to enable core engine features.
|
||||||
/// This is the preferred constructor for most use cases.
|
/// This is the preferred constructor for most use cases.
|
||||||
///
|
|
||||||
/// This calls [`App::add_default_schedules`].
|
|
||||||
pub fn new() -> App {
|
pub fn new() -> App {
|
||||||
App::default()
|
App::default()
|
||||||
}
|
}
|
||||||
|
@ -229,8 +221,7 @@ impl App {
|
||||||
sub_apps: HashMap::default(),
|
sub_apps: HashMap::default(),
|
||||||
plugin_registry: Vec::default(),
|
plugin_registry: Vec::default(),
|
||||||
plugin_name_added: Default::default(),
|
plugin_name_added: Default::default(),
|
||||||
default_schedule_label: Box::new(CoreSchedule::Main),
|
main_schedule_label: Box::new(Main),
|
||||||
outer_schedule_label: Box::new(CoreSchedule::Outer),
|
|
||||||
building_plugin_depth: 0,
|
building_plugin_depth: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,9 +231,8 @@ impl App {
|
||||||
/// This method also updates sub apps.
|
/// This method also updates sub apps.
|
||||||
/// See [`insert_sub_app`](Self::insert_sub_app) for more details.
|
/// See [`insert_sub_app`](Self::insert_sub_app) for more details.
|
||||||
///
|
///
|
||||||
/// The schedule run by this method is determined by the [`outer_schedule_label`](App) field.
|
/// The schedule run by this method is determined by the [`main_schedule_label`](App) field.
|
||||||
/// In normal usage, this is [`CoreSchedule::Outer`], which will run [`CoreSchedule::Startup`]
|
/// By default this is [`Main`].
|
||||||
/// the first time the app is run, then [`CoreSchedule::Main`] on every call of this method.
|
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -251,7 +241,7 @@ impl App {
|
||||||
{
|
{
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
let _bevy_frame_update_span = info_span!("main app").entered();
|
let _bevy_frame_update_span = info_span!("main app").entered();
|
||||||
self.world.run_schedule_ref(&*self.outer_schedule_label);
|
self.world.run_schedule_ref(&*self.main_schedule_label);
|
||||||
}
|
}
|
||||||
for (_label, sub_app) in self.sub_apps.iter_mut() {
|
for (_label, sub_app) in self.sub_apps.iter_mut() {
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
|
@ -317,13 +307,13 @@ impl App {
|
||||||
|
|
||||||
/// Adds [`State<S>`] and [`NextState<S>`] resources, [`OnEnter`] and [`OnExit`] schedules
|
/// Adds [`State<S>`] and [`NextState<S>`] resources, [`OnEnter`] and [`OnExit`] schedules
|
||||||
/// for each state variant (if they don't already exist), an instance of [`apply_state_transition::<S>`] in
|
/// for each state variant (if they don't already exist), an instance of [`apply_state_transition::<S>`] in
|
||||||
/// [`CoreSet::StateTransitions`] so that transitions happen before [`CoreSet::Update`] and
|
/// [`StateTransition`] so that transitions happen before [`Update`] and
|
||||||
/// a instance of [`run_enter_schedule::<S>`] in [`CoreSet::StateTransitions`] with a
|
/// a instance of [`run_enter_schedule::<S>`] in [`StateTransition`] with a
|
||||||
/// [`run_once`](`run_once_condition`) condition to run the on enter schedule of the
|
/// [`run_once`](`run_once_condition`) condition to run the on enter schedule of the
|
||||||
/// initial state.
|
/// initial state.
|
||||||
///
|
///
|
||||||
/// This also adds an [`OnUpdate`] system set for each state variant,
|
/// This also adds an [`OnUpdate`] system set for each state variant,
|
||||||
/// which runs during [`CoreSet::Update`] after the transitions are applied.
|
/// which runs during [`Update`] after the transitions are applied.
|
||||||
/// These system sets only run if the [`State<S>`] resource matches the respective state variant.
|
/// These system sets only run if the [`State<S>`] resource matches the respective state variant.
|
||||||
///
|
///
|
||||||
/// If you would like to control how other systems run based on the current state,
|
/// If you would like to control how other systems run based on the current state,
|
||||||
|
@ -332,31 +322,19 @@ impl App {
|
||||||
/// Note that you can also apply state transitions at other points in the schedule
|
/// Note that you can also apply state transitions at other points in the schedule
|
||||||
/// by adding the [`apply_state_transition`] system manually.
|
/// by adding the [`apply_state_transition`] system manually.
|
||||||
pub fn add_state<S: States>(&mut self) -> &mut Self {
|
pub fn add_state<S: States>(&mut self) -> &mut Self {
|
||||||
self.init_resource::<State<S>>();
|
self.init_resource::<State<S>>()
|
||||||
self.init_resource::<NextState<S>>();
|
.init_resource::<NextState<S>>()
|
||||||
|
.add_systems(
|
||||||
let mut schedules = self.world.resource_mut::<Schedules>();
|
StateTransition,
|
||||||
|
(
|
||||||
let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) else {
|
run_enter_schedule::<S>.run_if(run_once_condition()),
|
||||||
let schedule_label = &self.default_schedule_label;
|
apply_state_transition::<S>,
|
||||||
panic!("Default schedule {schedule_label:?} does not exist.")
|
)
|
||||||
};
|
.chain(),
|
||||||
|
);
|
||||||
default_schedule.add_systems(
|
|
||||||
(
|
|
||||||
run_enter_schedule::<S>.run_if(run_once_condition()),
|
|
||||||
apply_state_transition::<S>,
|
|
||||||
)
|
|
||||||
.chain()
|
|
||||||
.in_base_set(CoreSet::StateTransitions),
|
|
||||||
);
|
|
||||||
|
|
||||||
for variant in S::variants() {
|
for variant in S::variants() {
|
||||||
default_schedule.configure_set(
|
self.configure_set(Update, OnUpdate(variant.clone()).run_if(in_state(variant)));
|
||||||
OnUpdate(variant.clone())
|
|
||||||
.in_base_set(CoreSet::Update)
|
|
||||||
.run_if(in_state(variant)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The OnEnter, OnExit, and OnTransition schedules are lazily initialized
|
// The OnEnter, OnExit, and OnTransition schedules are lazily initialized
|
||||||
|
@ -382,30 +360,15 @@ impl App {
|
||||||
/// #
|
/// #
|
||||||
/// app.add_system(my_system);
|
/// app.add_system(my_system);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_system<M>(&mut self, system: impl IntoSystemAppConfig<M>) -> &mut Self {
|
#[deprecated(
|
||||||
let mut schedules = self.world.resource_mut::<Schedules>();
|
since = "0.11.0",
|
||||||
|
note = "Please use `add_systems` instead. If you didn't change the default base set, you should use `add_systems(Update, your_system).`"
|
||||||
let SystemAppConfig { system, schedule } = system.into_app_config();
|
)]
|
||||||
|
pub fn add_system<M>(&mut self, system: impl IntoSystemConfigs<M>) -> &mut Self {
|
||||||
if let Some(schedule_label) = schedule {
|
self.add_systems(Update, system)
|
||||||
if let Some(schedule) = schedules.get_mut(&*schedule_label) {
|
|
||||||
schedule.add_system(system);
|
|
||||||
} else {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.add_system(system);
|
|
||||||
schedules.insert(schedule_label, schedule);
|
|
||||||
}
|
|
||||||
} else if let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) {
|
|
||||||
default_schedule.add_system(system);
|
|
||||||
} else {
|
|
||||||
let schedule_label = &self.default_schedule_label;
|
|
||||||
panic!("Default schedule {schedule_label:?} does not exist.")
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a system to the default system set and schedule of the app's [`Schedules`].
|
/// Adds a system to the given schedule in this app's [`Schedules`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -418,36 +381,27 @@ impl App {
|
||||||
/// # fn system_b() {}
|
/// # fn system_b() {}
|
||||||
/// # fn system_c() {}
|
/// # fn system_c() {}
|
||||||
/// #
|
/// #
|
||||||
/// app.add_systems((system_a, system_b, system_c));
|
/// app.add_systems(Update, (system_a, system_b, system_c));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_systems<M>(&mut self, systems: impl IntoSystemAppConfigs<M>) -> &mut Self {
|
pub fn add_systems<M>(
|
||||||
|
&mut self,
|
||||||
|
schedule: impl ScheduleLabel,
|
||||||
|
systems: impl IntoSystemConfigs<M>,
|
||||||
|
) -> &mut Self {
|
||||||
let mut schedules = self.world.resource_mut::<Schedules>();
|
let mut schedules = self.world.resource_mut::<Schedules>();
|
||||||
|
|
||||||
match systems.into_app_configs().0 {
|
if let Some(schedule) = schedules.get_mut(&schedule) {
|
||||||
crate::InnerConfigs::Blanket { systems, schedule } => {
|
schedule.add_systems(systems);
|
||||||
let schedule = if let Some(label) = schedule {
|
} else {
|
||||||
schedules
|
let mut new_schedule = Schedule::new();
|
||||||
.get_mut(&*label)
|
new_schedule.add_systems(systems);
|
||||||
.unwrap_or_else(|| panic!("Schedule '{label:?}' does not exist."))
|
schedules.insert(schedule, new_schedule);
|
||||||
} else {
|
|
||||||
let label = &*self.default_schedule_label;
|
|
||||||
schedules
|
|
||||||
.get_mut(label)
|
|
||||||
.unwrap_or_else(|| panic!("Default schedule '{label:?}' does not exist."))
|
|
||||||
};
|
|
||||||
schedule.add_systems(systems);
|
|
||||||
}
|
|
||||||
crate::InnerConfigs::Granular(systems) => {
|
|
||||||
for system in systems {
|
|
||||||
self.add_system(system);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a system to [`CoreSchedule::Startup`].
|
/// Adds a system to [`Startup`].
|
||||||
///
|
///
|
||||||
/// These systems will run exactly once, at the start of the [`App`]'s lifecycle.
|
/// These systems will run exactly once, at the start of the [`App`]'s lifecycle.
|
||||||
/// To add a system that runs every frame, see [`add_system`](Self::add_system).
|
/// To add a system that runs every frame, see [`add_system`](Self::add_system).
|
||||||
|
@ -463,13 +417,17 @@ impl App {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .add_startup_system(my_startup_system);
|
/// .add_systems(Startup, my_startup_system);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_startup_system<M>(&mut self, system: impl IntoSystemConfig<M>) -> &mut Self {
|
#[deprecated(
|
||||||
self.add_system(system.in_schedule(CoreSchedule::Startup))
|
since = "0.11.0",
|
||||||
|
note = "Please use `add_systems` instead. If you didn't change the default base set, you should use `add_systems(Startup, your_system).`"
|
||||||
|
)]
|
||||||
|
pub fn add_startup_system<M>(&mut self, system: impl IntoSystemConfigs<M>) -> &mut Self {
|
||||||
|
self.add_systems(Startup, system)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a collection of systems to [`CoreSchedule::Startup`].
|
/// Adds a collection of systems to [`Startup`].
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -482,88 +440,58 @@ impl App {
|
||||||
/// # fn startup_system_b() {}
|
/// # fn startup_system_b() {}
|
||||||
/// # fn startup_system_c() {}
|
/// # fn startup_system_c() {}
|
||||||
/// #
|
/// #
|
||||||
/// app.add_startup_systems((
|
/// app.add_systems(Startup, (
|
||||||
/// startup_system_a,
|
/// startup_system_a,
|
||||||
/// startup_system_b,
|
/// startup_system_b,
|
||||||
/// startup_system_c,
|
/// startup_system_c,
|
||||||
/// ));
|
/// ));
|
||||||
/// ```
|
/// ```
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.11.0",
|
||||||
|
note = "Please use `add_systems` instead. If you didn't change the default base set, you should use `add_systems(Startup, your_system).`"
|
||||||
|
)]
|
||||||
pub fn add_startup_systems<M>(&mut self, systems: impl IntoSystemConfigs<M>) -> &mut Self {
|
pub fn add_startup_systems<M>(&mut self, systems: impl IntoSystemConfigs<M>) -> &mut Self {
|
||||||
self.add_systems(systems.into_configs().in_schedule(CoreSchedule::Startup))
|
self.add_systems(Startup, systems.into_configs())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures a system set in the default schedule, adding the set if it does not exist.
|
/// Configures a system set in the default schedule, adding the set if it does not exist.
|
||||||
pub fn configure_set(&mut self, set: impl IntoSystemSetConfig) -> &mut Self {
|
pub fn configure_set(
|
||||||
self.world
|
&mut self,
|
||||||
.resource_mut::<Schedules>()
|
schedule: impl ScheduleLabel,
|
||||||
.get_mut(&*self.default_schedule_label)
|
set: impl IntoSystemSetConfig,
|
||||||
.unwrap()
|
) -> &mut Self {
|
||||||
.configure_set(set);
|
let mut schedules = self.world.resource_mut::<Schedules>();
|
||||||
|
if let Some(schedule) = schedules.get_mut(&schedule) {
|
||||||
|
schedule.configure_set(set);
|
||||||
|
} else {
|
||||||
|
let mut new_schedule = Schedule::new();
|
||||||
|
new_schedule.configure_set(set);
|
||||||
|
schedules.insert(schedule, new_schedule);
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures a collection of system sets in the default schedule, adding any sets that do not exist.
|
/// Configures a collection of system sets in the default schedule, adding any sets that do not exist.
|
||||||
pub fn configure_sets(&mut self, sets: impl IntoSystemSetConfigs) -> &mut Self {
|
pub fn configure_sets(
|
||||||
self.world
|
&mut self,
|
||||||
.resource_mut::<Schedules>()
|
schedule: impl ScheduleLabel,
|
||||||
.get_mut(&*self.default_schedule_label)
|
sets: impl IntoSystemSetConfigs,
|
||||||
.unwrap()
|
) -> &mut Self {
|
||||||
.configure_sets(sets);
|
let mut schedules = self.world.resource_mut::<Schedules>();
|
||||||
self
|
if let Some(schedule) = schedules.get_mut(&schedule) {
|
||||||
}
|
schedule.configure_sets(sets);
|
||||||
|
} else {
|
||||||
/// Adds standardized schedules and labels to an [`App`].
|
let mut new_schedule = Schedule::new();
|
||||||
///
|
new_schedule.configure_sets(sets);
|
||||||
/// Adding these schedules is necessary to make almost all core engine features work.
|
schedules.insert(schedule, new_schedule);
|
||||||
/// This is typically done implicitly by calling `App::default`, which is in turn called by
|
|
||||||
/// [`App::new`].
|
|
||||||
///
|
|
||||||
/// The schedules added are defined in the [`CoreSchedule`] enum,
|
|
||||||
/// and have a starting configuration defined by:
|
|
||||||
///
|
|
||||||
/// - [`CoreSchedule::Outer`]: uses [`CoreSchedule::outer_schedule`]
|
|
||||||
/// - [`CoreSchedule::Startup`]: uses [`StartupSet::base_schedule`]
|
|
||||||
/// - [`CoreSchedule::Main`]: uses [`CoreSet::base_schedule`]
|
|
||||||
/// - [`CoreSchedule::FixedUpdate`]: no starting configuration
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use bevy_app::App;
|
|
||||||
/// use bevy_ecs::schedule::Schedules;
|
|
||||||
///
|
|
||||||
/// let app = App::empty()
|
|
||||||
/// .init_resource::<Schedules>()
|
|
||||||
/// .add_default_schedules()
|
|
||||||
/// .update();
|
|
||||||
/// ```
|
|
||||||
pub fn add_default_schedules(&mut self) -> &mut Self {
|
|
||||||
self.add_schedule(CoreSchedule::Outer, CoreSchedule::outer_schedule());
|
|
||||||
self.add_schedule(CoreSchedule::Startup, StartupSet::base_schedule());
|
|
||||||
self.add_schedule(CoreSchedule::Main, CoreSet::base_schedule());
|
|
||||||
self.init_schedule(CoreSchedule::FixedUpdate);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// adds a single threaded outer schedule to the [`App`] that just runs the main schedule
|
|
||||||
pub fn add_simple_outer_schedule(&mut self) -> &mut Self {
|
|
||||||
fn run_main_schedule(world: &mut World) {
|
|
||||||
world.run_schedule(CoreSchedule::Main);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.edit_schedule(CoreSchedule::Outer, |schedule| {
|
|
||||||
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
|
|
||||||
schedule.add_system(run_main_schedule);
|
|
||||||
});
|
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Setup the application to manage events of type `T`.
|
/// Setup the application to manage events of type `T`.
|
||||||
///
|
///
|
||||||
/// This is done by adding a [`Resource`] of type [`Events::<T>`],
|
/// This is done by adding a [`Resource`] of type [`Events::<T>`],
|
||||||
/// and inserting an [`update_system`](Events::update_system) into [`CoreSet::First`].
|
/// and inserting an [`update_system`](Events::update_system) into [`First`].
|
||||||
///
|
///
|
||||||
/// See [`Events`] for defining events.
|
/// See [`Events`] for defining events.
|
||||||
///
|
///
|
||||||
|
@ -584,7 +512,7 @@ impl App {
|
||||||
{
|
{
|
||||||
if !self.world.contains_resource::<Events<T>>() {
|
if !self.world.contains_resource::<Events<T>>() {
|
||||||
self.init_resource::<Events<T>>()
|
self.init_resource::<Events<T>>()
|
||||||
.add_system(Events::<T>::update_system.in_base_set(CoreSet::First));
|
.add_systems(First, Events::<T>::update_system);
|
||||||
}
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -1025,7 +953,7 @@ mod tests {
|
||||||
system::Commands,
|
system::Commands,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{App, IntoSystemAppConfig, IntoSystemAppConfigs, Plugin};
|
use crate::{App, Plugin};
|
||||||
|
|
||||||
struct PluginA;
|
struct PluginA;
|
||||||
impl Plugin for PluginA {
|
impl Plugin for PluginA {
|
||||||
|
@ -1097,31 +1025,11 @@ mod tests {
|
||||||
commands.spawn_empty();
|
commands.spawn_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add_system_should_create_schedule_if_it_does_not_exist() {
|
|
||||||
let mut app = App::new();
|
|
||||||
app.add_system(foo.in_schedule(OnEnter(AppState::MainMenu)))
|
|
||||||
.add_state::<AppState>();
|
|
||||||
|
|
||||||
app.world.run_schedule(OnEnter(AppState::MainMenu));
|
|
||||||
assert_eq!(app.world.entities().len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add_system_should_create_schedule_if_it_does_not_exist2() {
|
|
||||||
let mut app = App::new();
|
|
||||||
app.add_state::<AppState>()
|
|
||||||
.add_system(foo.in_schedule(OnEnter(AppState::MainMenu)));
|
|
||||||
|
|
||||||
app.world.run_schedule(OnEnter(AppState::MainMenu));
|
|
||||||
assert_eq!(app.world.entities().len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_systems_should_create_schedule_if_it_does_not_exist() {
|
fn add_systems_should_create_schedule_if_it_does_not_exist() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_state::<AppState>()
|
app.add_state::<AppState>()
|
||||||
.add_systems((foo, bar).in_schedule(OnEnter(AppState::MainMenu)));
|
.add_systems(OnEnter(AppState::MainMenu), (foo, bar));
|
||||||
|
|
||||||
app.world.run_schedule(OnEnter(AppState::MainMenu));
|
app.world.run_schedule(OnEnter(AppState::MainMenu));
|
||||||
assert_eq!(app.world.entities().len(), 2);
|
assert_eq!(app.world.entities().len(), 2);
|
||||||
|
@ -1130,7 +1038,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn add_systems_should_create_schedule_if_it_does_not_exist2() {
|
fn add_systems_should_create_schedule_if_it_does_not_exist2() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_systems((foo, bar).in_schedule(OnEnter(AppState::MainMenu)))
|
app.add_systems(OnEnter(AppState::MainMenu), (foo, bar))
|
||||||
.add_state::<AppState>();
|
.add_state::<AppState>();
|
||||||
|
|
||||||
app.world.run_schedule(OnEnter(AppState::MainMenu));
|
app.world.run_schedule(OnEnter(AppState::MainMenu));
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{app::AppExit, App};
|
use crate::{app::AppExit, App, Update};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use bevy_ecs::prelude::Resource;
|
use bevy_ecs::prelude::Resource;
|
||||||
|
@ -47,7 +47,7 @@ pub(crate) fn setup_app(app: &mut App) -> &mut App {
|
||||||
};
|
};
|
||||||
|
|
||||||
app.insert_resource(config)
|
app.insert_resource(config)
|
||||||
.add_system(ci_testing_exit_after);
|
.add_systems(Update, ci_testing_exit_after);
|
||||||
|
|
||||||
app
|
app
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,294 +0,0 @@
|
||||||
use bevy_ecs::{
|
|
||||||
all_tuples,
|
|
||||||
schedule::{
|
|
||||||
BaseSystemSet, BoxedScheduleLabel, Condition, FreeSystemSet, IntoSystemConfig,
|
|
||||||
IntoSystemSet, ScheduleLabel, SystemConfig, SystemConfigs,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::CoreSchedule;
|
|
||||||
|
|
||||||
/// A [`System`] with [`App`]-aware scheduling metadata.
|
|
||||||
///
|
|
||||||
/// [`System`]: bevy_ecs::prelude::System
|
|
||||||
/// [`App`]: crate::App
|
|
||||||
pub struct SystemAppConfig {
|
|
||||||
pub(crate) system: SystemConfig,
|
|
||||||
pub(crate) schedule: Option<BoxedScheduleLabel>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Types that can be converted into a [`SystemAppConfig`].
|
|
||||||
///
|
|
||||||
/// This has been implemented for all `System<In = (), Out = ()>` trait objects
|
|
||||||
/// and all functions that convert into such.
|
|
||||||
pub trait IntoSystemAppConfig<Marker>: Sized {
|
|
||||||
/// Converts into a [`SystemAppConfig`].
|
|
||||||
fn into_app_config(self) -> SystemAppConfig;
|
|
||||||
|
|
||||||
/// Adds the system to the provided `schedule`.
|
|
||||||
///
|
|
||||||
/// If a schedule is not specified, it will be added to the [`App`]'s default schedule.
|
|
||||||
///
|
|
||||||
/// [`App`]: crate::App
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If the system has already been assigned to a schedule.
|
|
||||||
#[track_caller]
|
|
||||||
fn in_schedule(self, schedule: impl ScheduleLabel) -> SystemAppConfig {
|
|
||||||
let mut config = self.into_app_config();
|
|
||||||
if let Some(old_schedule) = &config.schedule {
|
|
||||||
panic!(
|
|
||||||
"Cannot add system to schedule '{schedule:?}': it is already in '{old_schedule:?}'."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
config.schedule = Some(Box::new(schedule));
|
|
||||||
|
|
||||||
config
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds the system to [`CoreSchedule::Startup`].
|
|
||||||
/// This is a shorthand for `self.in_schedule(CoreSchedule::Startup)`.
|
|
||||||
///
|
|
||||||
/// Systems in this schedule will run exactly once, at the start of the [`App`]'s lifecycle.
|
|
||||||
///
|
|
||||||
/// [`App`]: crate::App
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_app::prelude::*;
|
|
||||||
/// # use bevy_ecs::prelude::*;
|
|
||||||
/// #
|
|
||||||
/// fn my_startup_system(_commands: Commands) {
|
|
||||||
/// println!("My startup system");
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// App::new()
|
|
||||||
/// .add_system(my_startup_system.on_startup())
|
|
||||||
/// .run();
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If the system has already been assigned to a schedule.
|
|
||||||
#[inline]
|
|
||||||
fn on_startup(self) -> SystemAppConfig {
|
|
||||||
self.in_schedule(CoreSchedule::Startup)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystemConfig<(), Self> for SystemAppConfig {
|
|
||||||
fn into_config(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_set(self, set: impl FreeSystemSet) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.in_set(set),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(self, set: impl BaseSystemSet) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.in_base_set(set),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn no_default_base_set(self) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.no_default_base_set(),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before<M>(self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.before(set),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn after<M>(self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.after(set),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_if<P>(self, condition: impl Condition<P>) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.run_if(condition),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.ambiguous_with(set),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ambiguous_with_all(self) -> Self {
|
|
||||||
let Self { system, schedule } = self;
|
|
||||||
Self {
|
|
||||||
system: system.ambiguous_with_all(),
|
|
||||||
schedule,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystemAppConfig<()> for SystemAppConfig {
|
|
||||||
fn into_app_config(self) -> SystemAppConfig {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Marker, T> IntoSystemAppConfig<Marker> for T
|
|
||||||
where
|
|
||||||
T: IntoSystemConfig<Marker>,
|
|
||||||
{
|
|
||||||
fn into_app_config(self) -> SystemAppConfig {
|
|
||||||
SystemAppConfig {
|
|
||||||
system: self.into_config(),
|
|
||||||
schedule: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A collection of [`SystemAppConfig`]s.
|
|
||||||
pub struct SystemAppConfigs(pub(crate) InnerConfigs);
|
|
||||||
|
|
||||||
pub(crate) enum InnerConfigs {
|
|
||||||
/// This came from an instance of `SystemConfigs`.
|
|
||||||
/// All systems are in the same schedule.
|
|
||||||
Blanket {
|
|
||||||
systems: SystemConfigs,
|
|
||||||
schedule: Option<BoxedScheduleLabel>,
|
|
||||||
},
|
|
||||||
/// This came from several separate instances of `SystemAppConfig`.
|
|
||||||
/// Each system gets its own schedule.
|
|
||||||
Granular(Vec<SystemAppConfig>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Types that can convert into [`SystemAppConfigs`].
|
|
||||||
pub trait IntoSystemAppConfigs<Marker>: Sized {
|
|
||||||
/// Converts to [`SystemAppConfigs`].
|
|
||||||
fn into_app_configs(self) -> SystemAppConfigs;
|
|
||||||
|
|
||||||
/// Adds the systems to the provided `schedule`.
|
|
||||||
///
|
|
||||||
/// If a schedule with specified label does not exist, it will be created.
|
|
||||||
///
|
|
||||||
/// If a schedule with the specified label does not exist, an empty one will be created.
|
|
||||||
///
|
|
||||||
///
|
|
||||||
/// [`App`]: crate::App
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If any of the systems have already been assigned to a schedule.
|
|
||||||
#[track_caller]
|
|
||||||
fn in_schedule(self, label: impl ScheduleLabel) -> SystemAppConfigs {
|
|
||||||
let mut configs = self.into_app_configs();
|
|
||||||
|
|
||||||
match &mut configs.0 {
|
|
||||||
InnerConfigs::Blanket { schedule, .. } => {
|
|
||||||
if schedule.is_some() {
|
|
||||||
panic!(
|
|
||||||
"Cannot add systems to the schedule '{label:?}: they are already in '{schedule:?}'"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
*schedule = Some(Box::new(label));
|
|
||||||
}
|
|
||||||
InnerConfigs::Granular(configs) => {
|
|
||||||
for SystemAppConfig { schedule, .. } in configs {
|
|
||||||
if schedule.is_some() {
|
|
||||||
panic!(
|
|
||||||
"Cannot add system to the schedule '{label:?}': it is already in '{schedule:?}'."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
*schedule = Some(label.dyn_clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configs
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds the systems to [`CoreSchedule::Startup`].
|
|
||||||
/// This is a shorthand for `self.in_schedule(CoreSchedule::Startup)`.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_app::prelude::*;
|
|
||||||
/// # use bevy_ecs::prelude::*;
|
|
||||||
/// #
|
|
||||||
/// # let mut app = App::new();
|
|
||||||
/// # fn startup_system_a() {}
|
|
||||||
/// # fn startup_system_b() {}
|
|
||||||
/// # fn startup_system_c() {}
|
|
||||||
/// #
|
|
||||||
/// app.add_systems(
|
|
||||||
/// (
|
|
||||||
/// startup_system_a,
|
|
||||||
/// startup_system_b,
|
|
||||||
/// startup_system_c,
|
|
||||||
/// )
|
|
||||||
/// .on_startup()
|
|
||||||
/// );
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// If any of the systems have already been assigned to a schedule.
|
|
||||||
#[track_caller]
|
|
||||||
fn on_startup(self) -> SystemAppConfigs {
|
|
||||||
self.in_schedule(CoreSchedule::Startup)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystemAppConfigs<()> for SystemAppConfigs {
|
|
||||||
fn into_app_configs(self) -> SystemAppConfigs {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystemAppConfigs<()> for SystemConfigs {
|
|
||||||
fn into_app_configs(self) -> SystemAppConfigs {
|
|
||||||
SystemAppConfigs(InnerConfigs::Blanket {
|
|
||||||
systems: self,
|
|
||||||
schedule: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_system_collection {
|
|
||||||
($(($param: ident, $sys: ident)),*) => {
|
|
||||||
impl<$($param, $sys),*> IntoSystemAppConfigs<($($param,)*)> for ($($sys,)*)
|
|
||||||
where
|
|
||||||
$($sys: IntoSystemAppConfig<$param>),*
|
|
||||||
{
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn into_app_configs(self) -> SystemAppConfigs {
|
|
||||||
let ($($sys,)*) = self;
|
|
||||||
SystemAppConfigs(InnerConfigs::Granular(vec![$($sys.into_app_config(),)*]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
all_tuples!(impl_system_collection, 0, 15, P, S);
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod config;
|
mod main_schedule;
|
||||||
mod plugin;
|
mod plugin;
|
||||||
mod plugin_group;
|
mod plugin_group;
|
||||||
mod schedule_runner;
|
mod schedule_runner;
|
||||||
|
@ -13,7 +13,7 @@ mod ci_testing;
|
||||||
|
|
||||||
pub use app::*;
|
pub use app::*;
|
||||||
pub use bevy_derive::DynamicPlugin;
|
pub use bevy_derive::DynamicPlugin;
|
||||||
pub use config::*;
|
pub use main_schedule::*;
|
||||||
pub use plugin::*;
|
pub use plugin::*;
|
||||||
pub use plugin_group::*;
|
pub use plugin_group::*;
|
||||||
pub use schedule_runner::*;
|
pub use schedule_runner::*;
|
||||||
|
@ -26,197 +26,10 @@ pub mod prelude {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
app::App,
|
app::App,
|
||||||
config::{IntoSystemAppConfig, IntoSystemAppConfigs},
|
main_schedule::{
|
||||||
CoreSchedule, CoreSet, DynamicPlugin, Plugin, PluginGroup, StartupSet,
|
First, FixedUpdate, Last, Main, PostStartup, PostUpdate, PreStartup, PreUpdate,
|
||||||
|
Startup, StateTransition, Update,
|
||||||
|
},
|
||||||
|
DynamicPlugin, Plugin, PluginGroup,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
use bevy_ecs::{
|
|
||||||
schedule::{
|
|
||||||
apply_system_buffers, IntoSystemConfig, IntoSystemSetConfigs, Schedule, ScheduleLabel,
|
|
||||||
SystemSet,
|
|
||||||
},
|
|
||||||
system::Local,
|
|
||||||
world::World,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The names of the default [`App`] schedules.
|
|
||||||
///
|
|
||||||
/// The corresponding [`Schedule`](bevy_ecs::schedule::Schedule) objects are added by [`App::add_default_schedules`].
|
|
||||||
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub enum CoreSchedule {
|
|
||||||
/// The schedule that runs once when the app starts.
|
|
||||||
Startup,
|
|
||||||
/// The schedule that contains the app logic that is evaluated each tick of [`App::update()`].
|
|
||||||
Main,
|
|
||||||
/// The schedule that controls which schedules run.
|
|
||||||
///
|
|
||||||
/// This is typically created using the [`CoreSchedule::outer_schedule`] method,
|
|
||||||
/// and does not need to manipulated during ordinary use.
|
|
||||||
Outer,
|
|
||||||
/// The schedule that contains systems which only run after a fixed period of time has elapsed.
|
|
||||||
///
|
|
||||||
/// The exclusive `run_fixed_update_schedule` system runs this schedule during the [`CoreSet::FixedUpdate`] system set.
|
|
||||||
FixedUpdate,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CoreSchedule {
|
|
||||||
/// An exclusive system that controls which schedule should be running.
|
|
||||||
///
|
|
||||||
/// [`CoreSchedule::Main`] is always run.
|
|
||||||
///
|
|
||||||
/// If this is the first time this system has been run, [`CoreSchedule::Startup`] will run before [`CoreSchedule::Main`].
|
|
||||||
pub fn outer_loop(world: &mut World, mut run_at_least_once: Local<bool>) {
|
|
||||||
if !*run_at_least_once {
|
|
||||||
world.run_schedule(CoreSchedule::Startup);
|
|
||||||
*run_at_least_once = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
world.run_schedule(CoreSchedule::Main);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes a single threaded schedule for [`CoreSchedule::Outer`] that contains the [`outer_loop`](CoreSchedule::outer_loop) system.
|
|
||||||
pub fn outer_schedule() -> Schedule {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
|
|
||||||
schedule.add_system(Self::outer_loop);
|
|
||||||
schedule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The names of the default [`App`] system sets.
|
|
||||||
///
|
|
||||||
/// These are ordered in the same order they are listed.
|
|
||||||
///
|
|
||||||
/// The corresponding [`SystemSets`](bevy_ecs::schedule::SystemSet) are added by [`App::add_default_schedules`].
|
|
||||||
///
|
|
||||||
/// The `*Flush` sets are assigned to the copy of [`apply_system_buffers`]
|
|
||||||
/// that runs immediately after the matching system set.
|
|
||||||
/// These can be useful for ordering, but you almost never want to add your systems to these sets.
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
|
|
||||||
#[system_set(base)]
|
|
||||||
pub enum CoreSet {
|
|
||||||
/// Runs before all other members of this set.
|
|
||||||
First,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `First`.
|
|
||||||
FirstFlush,
|
|
||||||
/// Runs before [`CoreSet::Update`].
|
|
||||||
PreUpdate,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `PreUpdate`.
|
|
||||||
PreUpdateFlush,
|
|
||||||
/// Applies [`State`](bevy_ecs::schedule::State) transitions
|
|
||||||
StateTransitions,
|
|
||||||
/// Runs systems that should only occur after a fixed period of time.
|
|
||||||
///
|
|
||||||
/// The `run_fixed_update_schedule` system runs the [`CoreSchedule::FixedUpdate`] system in this system set.
|
|
||||||
FixedUpdate,
|
|
||||||
/// Responsible for doing most app logic. Systems should be registered here by default.
|
|
||||||
Update,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `Update`.
|
|
||||||
UpdateFlush,
|
|
||||||
/// Runs after [`CoreSet::Update`].
|
|
||||||
PostUpdate,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `PostUpdate`.
|
|
||||||
PostUpdateFlush,
|
|
||||||
/// Runs after all other members of this set.
|
|
||||||
Last,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `Last`.
|
|
||||||
LastFlush,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CoreSet {
|
|
||||||
/// Sets up the base structure of [`CoreSchedule::Main`].
|
|
||||||
///
|
|
||||||
/// The sets defined in this enum are configured to run in order,
|
|
||||||
/// and a copy of [`apply_system_buffers`] is inserted into each `*Flush` set.
|
|
||||||
pub fn base_schedule() -> Schedule {
|
|
||||||
use CoreSet::*;
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
|
|
||||||
// Create "stage-like" structure using buffer flushes + ordering
|
|
||||||
schedule
|
|
||||||
.set_default_base_set(Update)
|
|
||||||
.add_systems((
|
|
||||||
apply_system_buffers.in_base_set(FirstFlush),
|
|
||||||
apply_system_buffers.in_base_set(PreUpdateFlush),
|
|
||||||
apply_system_buffers.in_base_set(UpdateFlush),
|
|
||||||
apply_system_buffers.in_base_set(PostUpdateFlush),
|
|
||||||
apply_system_buffers.in_base_set(LastFlush),
|
|
||||||
))
|
|
||||||
.configure_sets(
|
|
||||||
(
|
|
||||||
First,
|
|
||||||
FirstFlush,
|
|
||||||
PreUpdate,
|
|
||||||
PreUpdateFlush,
|
|
||||||
StateTransitions,
|
|
||||||
FixedUpdate,
|
|
||||||
Update,
|
|
||||||
UpdateFlush,
|
|
||||||
PostUpdate,
|
|
||||||
PostUpdateFlush,
|
|
||||||
Last,
|
|
||||||
LastFlush,
|
|
||||||
)
|
|
||||||
.chain(),
|
|
||||||
);
|
|
||||||
schedule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The names of the default [`App`] startup sets, which live in [`CoreSchedule::Startup`].
|
|
||||||
///
|
|
||||||
/// The corresponding [`SystemSets`](bevy_ecs::schedule::SystemSet) are added by [`App::add_default_schedules`].
|
|
||||||
///
|
|
||||||
/// The `*Flush` sets are assigned to the copy of [`apply_system_buffers`]
|
|
||||||
/// that runs immediately after the matching system set.
|
|
||||||
/// These can be useful for ordering, but you almost never want to add your systems to these sets.
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
|
|
||||||
#[system_set(base)]
|
|
||||||
pub enum StartupSet {
|
|
||||||
/// Runs once before [`StartupSet::Startup`].
|
|
||||||
PreStartup,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `PreStartup`.
|
|
||||||
PreStartupFlush,
|
|
||||||
/// Runs once when an [`App`] starts up.
|
|
||||||
Startup,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `Startup`.
|
|
||||||
StartupFlush,
|
|
||||||
/// Runs once after [`StartupSet::Startup`].
|
|
||||||
PostStartup,
|
|
||||||
/// The copy of [`apply_system_buffers`] that runs immediately after `PostStartup`.
|
|
||||||
PostStartupFlush,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StartupSet {
|
|
||||||
/// Sets up the base structure of [`CoreSchedule::Startup`].
|
|
||||||
///
|
|
||||||
/// The sets defined in this enum are configured to run in order,
|
|
||||||
/// and a copy of [`apply_system_buffers`] is inserted into each `*Flush` set.
|
|
||||||
pub fn base_schedule() -> Schedule {
|
|
||||||
use StartupSet::*;
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.set_default_base_set(Startup);
|
|
||||||
|
|
||||||
// Create "stage-like" structure using buffer flushes + ordering
|
|
||||||
schedule.add_systems((
|
|
||||||
apply_system_buffers.in_base_set(PreStartupFlush),
|
|
||||||
apply_system_buffers.in_base_set(StartupFlush),
|
|
||||||
apply_system_buffers.in_base_set(PostStartupFlush),
|
|
||||||
));
|
|
||||||
|
|
||||||
schedule.configure_sets(
|
|
||||||
(
|
|
||||||
PreStartup,
|
|
||||||
PreStartupFlush,
|
|
||||||
Startup,
|
|
||||||
StartupFlush,
|
|
||||||
PostStartup,
|
|
||||||
PostStartupFlush,
|
|
||||||
)
|
|
||||||
.chain(),
|
|
||||||
);
|
|
||||||
|
|
||||||
schedule
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
168
crates/bevy_app/src/main_schedule.rs
Normal file
168
crates/bevy_app/src/main_schedule.rs
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
use crate::{App, Plugin};
|
||||||
|
use bevy_ecs::{
|
||||||
|
schedule::{ExecutorKind, Schedule, ScheduleLabel},
|
||||||
|
system::{Local, Resource},
|
||||||
|
world::{Mut, World},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The schedule that contains the app logic that is evaluated each tick of [`App::update()`].
|
||||||
|
///
|
||||||
|
/// By default, it will run the following schedules in the given order:
|
||||||
|
///
|
||||||
|
/// On the first run of the schedule (and only on the first run), it will run:
|
||||||
|
/// * [`PreStartup`]
|
||||||
|
/// * [`Startup`]
|
||||||
|
/// * [`PostStartup`]
|
||||||
|
///
|
||||||
|
/// Then it will run:
|
||||||
|
/// * [`First`]
|
||||||
|
/// * [`PreUpdate`]
|
||||||
|
/// * [`StateTransition`]
|
||||||
|
/// * [`RunFixedUpdateLoop`]
|
||||||
|
/// * This will run [`FixedUpdate`] zero to many times, based on how much time has elapsed.
|
||||||
|
/// * [`Update`]
|
||||||
|
/// * [`PostUpdate`]
|
||||||
|
/// * [`Last`]
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Main;
|
||||||
|
|
||||||
|
/// The schedule that runs before [`Startup`].
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PreStartup;
|
||||||
|
|
||||||
|
/// The schedule that runs once when the app starts.
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Startup;
|
||||||
|
|
||||||
|
/// The schedule that runs once after [`Startup`].
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PostStartup;
|
||||||
|
|
||||||
|
/// Runs first in the schedule.
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct First;
|
||||||
|
|
||||||
|
/// The schedule that contains logic that must run before [`Update`]. For example, a system that reads raw keyboard
|
||||||
|
/// input OS events into an `Events` resource. This enables systems in [`Update`] to consume the events from the `Events`
|
||||||
|
/// resource without actually knowing about (or taking a direct scheduler dependency on) the "os-level keyboard event sytsem".
|
||||||
|
///
|
||||||
|
/// [`PreUpdate`] exists to do "engine/plugin preparation work" that ensures the APIs consumed in [`Update`] are "ready".
|
||||||
|
/// [`PreUpdate`] abstracts out "pre work implementation details".
|
||||||
|
///
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PreUpdate;
|
||||||
|
|
||||||
|
/// Runs [state transitions](bevy_ecs::schedule::States).
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct StateTransition;
|
||||||
|
|
||||||
|
/// Runs the [`FixedUpdate`] schedule in a loop according until all relevant elapsed time has been "consumed".
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct RunFixedUpdateLoop;
|
||||||
|
|
||||||
|
/// The schedule that contains systems which only run after a fixed period of time has elapsed.
|
||||||
|
///
|
||||||
|
/// The exclusive `run_fixed_update_schedule` system runs this schedule.
|
||||||
|
/// This is run by the [`RunFixedUpdateLoop`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct FixedUpdate;
|
||||||
|
|
||||||
|
/// The schedule that contains app logic.
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Update;
|
||||||
|
|
||||||
|
/// The schedule that contains logic that must run after [`Update`]. For example, synchronizing "local transforms" in a hierarchy
|
||||||
|
/// to "global" absolute transforms. This enables the [`PostUpdate`] transform-sync system to react to "local transform" changes in
|
||||||
|
/// [`Update`] without the [`Update`] systems needing to know about (or add scheduler dependencies for) the "global transform sync system".
|
||||||
|
///
|
||||||
|
/// [`PostUpdate`] exists to do "engine/plugin response work" to things that happened in [`Update`].
|
||||||
|
/// [`PostUpdate`] abstracts out "implementation details" from users defining systems in [`Update`].
|
||||||
|
///
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PostUpdate;
|
||||||
|
|
||||||
|
/// Runs last in the schedule.
|
||||||
|
/// This is run by the [`Main`] schedule.
|
||||||
|
#[derive(ScheduleLabel, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Last;
|
||||||
|
|
||||||
|
/// Defines the schedules to be run for the [`Main`] schedule, including
|
||||||
|
/// their order.
|
||||||
|
#[derive(Resource, Debug)]
|
||||||
|
pub struct MainScheduleOrder {
|
||||||
|
/// The labels to run for the [`Main`] schedule (in the order they will be run).
|
||||||
|
pub labels: Vec<Box<dyn ScheduleLabel>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MainScheduleOrder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
labels: vec![
|
||||||
|
Box::new(First),
|
||||||
|
Box::new(PreUpdate),
|
||||||
|
Box::new(StateTransition),
|
||||||
|
Box::new(RunFixedUpdateLoop),
|
||||||
|
Box::new(Update),
|
||||||
|
Box::new(PostUpdate),
|
||||||
|
Box::new(Last),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MainScheduleOrder {
|
||||||
|
/// Adds the given `schedule` after the `after` schedule
|
||||||
|
pub fn insert_after(&mut self, after: impl ScheduleLabel, schedule: impl ScheduleLabel) {
|
||||||
|
let index = self
|
||||||
|
.labels
|
||||||
|
.iter()
|
||||||
|
.position(|current| (**current).eq(&after))
|
||||||
|
.unwrap_or_else(|| panic!("Expected {after:?} to exist"));
|
||||||
|
self.labels.insert(index + 1, Box::new(schedule));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Main {
|
||||||
|
/// A system that runs the "main schedule"
|
||||||
|
pub fn run_main(world: &mut World, mut run_at_least_once: Local<bool>) {
|
||||||
|
if !*run_at_least_once {
|
||||||
|
let _ = world.try_run_schedule(PreStartup);
|
||||||
|
let _ = world.try_run_schedule(Startup);
|
||||||
|
let _ = world.try_run_schedule(PostStartup);
|
||||||
|
*run_at_least_once = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
world.resource_scope(|world, order: Mut<MainScheduleOrder>| {
|
||||||
|
for label in &order.labels {
|
||||||
|
let _ = world.try_run_schedule_ref(&**label);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initializes the [`Main`] schedule, sub schedules, and resources for a given [`App`].
|
||||||
|
pub struct MainSchedulePlugin;
|
||||||
|
|
||||||
|
impl Plugin for MainSchedulePlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
// simple "facilitator" schedules benefit from simpler single threaded scheduling
|
||||||
|
let mut main_schedule = Schedule::new();
|
||||||
|
main_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
|
||||||
|
let mut fixed_update_loop_schedule = Schedule::new();
|
||||||
|
fixed_update_loop_schedule.set_executor_kind(ExecutorKind::SingleThreaded);
|
||||||
|
|
||||||
|
app.add_schedule(Main, main_schedule)
|
||||||
|
.add_schedule(RunFixedUpdateLoop, fixed_update_loop_schedule)
|
||||||
|
.init_resource::<MainScheduleOrder>()
|
||||||
|
.add_systems(Main, Main::run_main);
|
||||||
|
}
|
||||||
|
}
|
|
@ -644,7 +644,7 @@ pub fn free_unused_assets_system(asset_server: Res<AssetServer>) {
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{loader::LoadedAsset, update_asset_storage_system};
|
use crate::{loader::LoadedAsset, update_asset_storage_system};
|
||||||
use bevy_app::App;
|
use bevy_app::{App, Update};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_utils::BoxedFuture;
|
use bevy_utils::BoxedFuture;
|
||||||
|
@ -852,10 +852,13 @@ mod test {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.insert_resource(assets);
|
app.insert_resource(assets);
|
||||||
app.insert_resource(asset_server);
|
app.insert_resource(asset_server);
|
||||||
app.add_systems((
|
app.add_systems(
|
||||||
free_unused_assets_system.in_set(FreeUnusedAssets),
|
Update,
|
||||||
update_asset_storage_system::<PngAsset>.after(FreeUnusedAssets),
|
(
|
||||||
));
|
free_unused_assets_system.in_set(FreeUnusedAssets),
|
||||||
|
update_asset_storage_system::<PngAsset>.after(FreeUnusedAssets),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
fn load_asset(path: AssetPath, world: &World) -> HandleUntyped {
|
fn load_asset(path: AssetPath, world: &World) -> HandleUntyped {
|
||||||
let asset_server = world.resource::<AssetServer>();
|
let asset_server = world.resource::<AssetServer>();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
update_asset_storage_system, Asset, AssetLoader, AssetServer, AssetSet, Handle, HandleId,
|
update_asset_storage_system, Asset, AssetEvents, AssetLoader, AssetServer, Handle, HandleId,
|
||||||
RefChange, ReflectAsset, ReflectHandle,
|
LoadAssets, RefChange, ReflectAsset, ReflectHandle,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, AppTypeRegistry};
|
use bevy_app::{App, AppTypeRegistry};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -331,10 +331,8 @@ impl AddAsset for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
self.insert_resource(assets)
|
self.insert_resource(assets)
|
||||||
.add_systems((
|
.add_systems(LoadAssets, update_asset_storage_system::<T>)
|
||||||
Assets::<T>::asset_event_system.in_base_set(AssetSet::AssetEvents),
|
.add_systems(AssetEvents, Assets::<T>::asset_event_system)
|
||||||
update_asset_storage_system::<T>.in_base_set(AssetSet::LoadAssets),
|
|
||||||
))
|
|
||||||
.register_type::<Handle<T>>()
|
.register_type::<Handle<T>>()
|
||||||
.add_event::<AssetEvent<T>>()
|
.add_event::<AssetEvent<T>>()
|
||||||
}
|
}
|
||||||
|
@ -362,9 +360,9 @@ impl AddAsset for App {
|
||||||
{
|
{
|
||||||
#[cfg(feature = "debug_asset_server")]
|
#[cfg(feature = "debug_asset_server")]
|
||||||
{
|
{
|
||||||
self.add_system(
|
self.add_systems(
|
||||||
crate::debug_asset_server::sync_debug_assets::<T>
|
bevy_app::Update,
|
||||||
.in_base_set(bevy_app::CoreSet::Update),
|
crate::debug_asset_server::sync_debug_assets::<T>,
|
||||||
);
|
);
|
||||||
let mut app = self
|
let mut app = self
|
||||||
.world
|
.world
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! Internal assets (e.g. shaders) are bundled directly into an application and can't be hot
|
//! Internal assets (e.g. shaders) are bundled directly into an application and can't be hot
|
||||||
//! reloaded using the conventional API.
|
//! reloaded using the conventional API.
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin, Update};
|
||||||
use bevy_ecs::{prelude::*, system::SystemState};
|
use bevy_ecs::{prelude::*, system::SystemState};
|
||||||
use bevy_tasks::{IoTaskPool, TaskPoolBuilder};
|
use bevy_tasks::{IoTaskPool, TaskPoolBuilder};
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
|
@ -75,7 +75,7 @@ impl Plugin for DebugAssetServerPlugin {
|
||||||
watch_for_changes: true,
|
watch_for_changes: true,
|
||||||
});
|
});
|
||||||
app.insert_non_send_resource(DebugAssetApp(debug_asset_app));
|
app.insert_non_send_resource(DebugAssetApp(debug_asset_app));
|
||||||
app.add_system(run_debug_asset_app);
|
app.add_systems(Update, run_debug_asset_app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,8 @@ impl<T: Asset> Default for AssetCountDiagnosticsPlugin<T> {
|
||||||
|
|
||||||
impl<T: Asset> Plugin for AssetCountDiagnosticsPlugin<T> {
|
impl<T: Asset> Plugin for AssetCountDiagnosticsPlugin<T> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_startup_system(Self::setup_system)
|
app.add_systems(Startup, Self::setup_system)
|
||||||
.add_system(Self::diagnostic_system);
|
.add_systems(Update, Self::diagnostic_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,18 +46,15 @@ pub use loader::*;
|
||||||
pub use path::*;
|
pub use path::*;
|
||||||
pub use reflect::*;
|
pub use reflect::*;
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::{prelude::*, MainScheduleOrder};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::schedule::ScheduleLabel;
|
||||||
|
|
||||||
/// [`SystemSet`]s for asset loading in an [`App`] schedule.
|
/// Asset storages are updated.
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)]
|
||||||
#[system_set(base)]
|
pub struct LoadAssets;
|
||||||
pub enum AssetSet {
|
/// Asset events are generated.
|
||||||
/// Asset storages are updated.
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)]
|
||||||
LoadAssets,
|
pub struct AssetEvents;
|
||||||
/// Asset events are generated.
|
|
||||||
AssetEvents,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds support for [`Assets`] to an App.
|
/// Adds support for [`Assets`] to an App.
|
||||||
///
|
///
|
||||||
|
@ -106,24 +103,19 @@ impl Plugin for AssetPlugin {
|
||||||
app.insert_resource(asset_server);
|
app.insert_resource(asset_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.register_type::<HandleId>();
|
app.register_type::<HandleId>()
|
||||||
|
.add_systems(PreUpdate, asset_server::free_unused_assets_system);
|
||||||
app.configure_set(
|
app.init_schedule(LoadAssets);
|
||||||
AssetSet::LoadAssets
|
app.init_schedule(AssetEvents);
|
||||||
.before(CoreSet::PreUpdate)
|
|
||||||
.after(CoreSet::First),
|
|
||||||
)
|
|
||||||
.configure_set(
|
|
||||||
AssetSet::AssetEvents
|
|
||||||
.after(CoreSet::PostUpdate)
|
|
||||||
.before(CoreSet::Last),
|
|
||||||
)
|
|
||||||
.add_system(asset_server::free_unused_assets_system.in_base_set(CoreSet::PreUpdate));
|
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(all(
|
||||||
feature = "filesystem_watcher",
|
feature = "filesystem_watcher",
|
||||||
all(not(target_arch = "wasm32"), not(target_os = "android"))
|
all(not(target_arch = "wasm32"), not(target_os = "android"))
|
||||||
))]
|
))]
|
||||||
app.add_system(io::filesystem_watcher_system.in_base_set(AssetSet::LoadAssets));
|
app.add_systems(LoadAssets, io::filesystem_watcher_system);
|
||||||
|
|
||||||
|
let mut order = app.world.resource_mut::<MainScheduleOrder>();
|
||||||
|
order.insert_after(First, LoadAssets);
|
||||||
|
order.insert_after(PostUpdate, AssetEvents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
//! # use bevy_ecs::{system::Res, event::EventWriter};
|
//! # use bevy_ecs::{system::Res, event::EventWriter};
|
||||||
//! # use bevy_audio::{Audio, AudioPlugin};
|
//! # use bevy_audio::{Audio, AudioPlugin};
|
||||||
//! # use bevy_asset::{AssetPlugin, AssetServer};
|
//! # use bevy_asset::{AssetPlugin, AssetServer};
|
||||||
//! # use bevy_app::{App, AppExit, NoopPluginGroup as MinimalPlugins};
|
//! # use bevy_app::{App, AppExit, NoopPluginGroup as MinimalPlugins, Startup};
|
||||||
//! fn main() {
|
//! fn main() {
|
||||||
//! App::new()
|
//! App::new()
|
||||||
//! .add_plugins(MinimalPlugins)
|
//! .add_plugins(MinimalPlugins)
|
||||||
//! .add_plugin(AssetPlugin::default())
|
//! .add_plugin(AssetPlugin::default())
|
||||||
//! .add_plugin(AudioPlugin)
|
//! .add_plugin(AudioPlugin)
|
||||||
//! .add_startup_system(play_background_audio)
|
//! .add_systems(Startup, play_background_audio)
|
||||||
//! .run();
|
//! .run();
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
|
@ -47,7 +47,6 @@ pub use sinks::*;
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_asset::{AddAsset, Asset};
|
use bevy_asset::{AddAsset, Asset};
|
||||||
use bevy_ecs::prelude::*;
|
|
||||||
|
|
||||||
/// Adds support for audio playback to a Bevy Application
|
/// Adds support for audio playback to a Bevy Application
|
||||||
///
|
///
|
||||||
|
@ -62,7 +61,7 @@ impl Plugin for AudioPlugin {
|
||||||
.add_asset::<AudioSink>()
|
.add_asset::<AudioSink>()
|
||||||
.add_asset::<SpatialAudioSink>()
|
.add_asset::<SpatialAudioSink>()
|
||||||
.init_resource::<Audio<AudioSource>>()
|
.init_resource::<Audio<AudioSource>>()
|
||||||
.add_system(play_queued_audio_system::<AudioSource>.in_base_set(CoreSet::PostUpdate));
|
.add_systems(PostUpdate, play_queued_audio_system::<AudioSource>);
|
||||||
|
|
||||||
#[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))]
|
#[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))]
|
||||||
app.init_asset_loader::<AudioLoader>();
|
app.init_asset_loader::<AudioLoader>();
|
||||||
|
@ -78,6 +77,6 @@ impl AddAudioSource for App {
|
||||||
self.add_asset::<T>()
|
self.add_asset::<T>()
|
||||||
.init_resource::<Audio<T>>()
|
.init_resource::<Audio<T>>()
|
||||||
.init_resource::<AudioOutput<T>>()
|
.init_resource::<AudioOutput<T>>()
|
||||||
.add_system(play_queued_audio_system::<T>.in_base_set(CoreSet::PostUpdate))
|
.add_systems(PostUpdate, play_queued_audio_system::<T>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,12 +102,12 @@ pub struct TaskPoolPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Plugin for TaskPoolPlugin {
|
impl Plugin for TaskPoolPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, _app: &mut App) {
|
||||||
// Setup the default bevy task pools
|
// Setup the default bevy task pools
|
||||||
self.task_pool_options.create_default_pools();
|
self.task_pool_options.create_default_pools();
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
app.add_system(tick_global_task_pools.in_base_set(bevy_app::CoreSet::Last));
|
_app.add_systems(Last, tick_global_task_pools);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
|
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
|
||||||
|
@ -124,7 +124,7 @@ fn tick_global_task_pools(_main_thread_marker: Option<NonSend<NonSendMarker>>) {
|
||||||
|
|
||||||
/// Maintains a count of frames rendered since the start of the application.
|
/// Maintains a count of frames rendered since the start of the application.
|
||||||
///
|
///
|
||||||
/// [`FrameCount`] is incremented during [`CoreSet::Last`], providing predictable
|
/// [`FrameCount`] is incremented during [`Last`], providing predictable
|
||||||
/// behaviour: it will be 0 during the first update, 1 during the next, and so forth.
|
/// behaviour: it will be 0 during the first update, 1 during the next, and so forth.
|
||||||
///
|
///
|
||||||
/// # Overflows
|
/// # Overflows
|
||||||
|
@ -142,7 +142,7 @@ pub struct FrameCountPlugin;
|
||||||
impl Plugin for FrameCountPlugin {
|
impl Plugin for FrameCountPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<FrameCount>();
|
app.init_resource::<FrameCount>();
|
||||||
app.add_system(update_frame_count.in_base_set(CoreSet::Last));
|
app.add_systems(Last, update_frame_count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,13 +7,7 @@ pub use settings::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings};
|
||||||
use crate::{core_2d, core_3d};
|
use crate::{core_2d, core_3d};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{load_internal_asset, HandleUntyped};
|
use bevy_asset::{load_internal_asset, HandleUntyped};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::prelude::*;
|
||||||
prelude::{Component, Entity},
|
|
||||||
query::{QueryState, With},
|
|
||||||
schedule::IntoSystemConfig,
|
|
||||||
system::{Commands, Query, Res, ResMut},
|
|
||||||
world::World,
|
|
||||||
};
|
|
||||||
use bevy_math::UVec2;
|
use bevy_math::UVec2;
|
||||||
use bevy_reflect::TypeUuid;
|
use bevy_reflect::TypeUuid;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
|
@ -27,7 +21,7 @@ use bevy_render::{
|
||||||
renderer::{RenderContext, RenderDevice},
|
renderer::{RenderContext, RenderDevice},
|
||||||
texture::{CachedTexture, TextureCache},
|
texture::{CachedTexture, TextureCache},
|
||||||
view::ViewTarget,
|
view::ViewTarget,
|
||||||
RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
use bevy_utils::tracing::info_span;
|
use bevy_utils::tracing::info_span;
|
||||||
|
@ -71,12 +65,15 @@ impl Plugin for BloomPlugin {
|
||||||
.init_resource::<BloomUpsamplingPipeline>()
|
.init_resource::<BloomUpsamplingPipeline>()
|
||||||
.init_resource::<SpecializedRenderPipelines<BloomDownsamplingPipeline>>()
|
.init_resource::<SpecializedRenderPipelines<BloomDownsamplingPipeline>>()
|
||||||
.init_resource::<SpecializedRenderPipelines<BloomUpsamplingPipeline>>()
|
.init_resource::<SpecializedRenderPipelines<BloomUpsamplingPipeline>>()
|
||||||
.add_systems((
|
.add_systems(
|
||||||
prepare_bloom_textures.in_set(RenderSet::Prepare),
|
Render,
|
||||||
prepare_downsampling_pipeline.in_set(RenderSet::Prepare),
|
(
|
||||||
prepare_upsampling_pipeline.in_set(RenderSet::Prepare),
|
prepare_bloom_textures.in_set(RenderSet::Prepare),
|
||||||
queue_bloom_bind_groups.in_set(RenderSet::Queue),
|
prepare_downsampling_pipeline.in_set(RenderSet::Prepare),
|
||||||
));
|
prepare_upsampling_pipeline.in_set(RenderSet::Prepare),
|
||||||
|
queue_bloom_bind_groups.in_set(RenderSet::Queue),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Add bloom to the 3d render graph
|
// Add bloom to the 3d render graph
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub mod graph {
|
||||||
pub use camera_2d::*;
|
pub use camera_2d::*;
|
||||||
pub use main_pass_2d_node::*;
|
pub use main_pass_2d_node::*;
|
||||||
|
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::Camera,
|
camera::Camera,
|
||||||
|
@ -31,7 +31,7 @@ use bevy_render::{
|
||||||
DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase,
|
DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase,
|
||||||
},
|
},
|
||||||
render_resource::CachedRenderPipelineId,
|
render_resource::CachedRenderPipelineId,
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_utils::FloatOrd;
|
use bevy_utils::FloatOrd;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
@ -52,13 +52,16 @@ impl Plugin for Core2dPlugin {
|
||||||
|
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<DrawFunctions<Transparent2d>>()
|
.init_resource::<DrawFunctions<Transparent2d>>()
|
||||||
.add_systems((
|
.add_systems(ExtractSchedule, extract_core_2d_camera_phases)
|
||||||
extract_core_2d_camera_phases.in_schedule(ExtractSchedule),
|
.add_systems(
|
||||||
sort_phase_system::<Transparent2d>.in_set(RenderSet::PhaseSort),
|
Render,
|
||||||
batch_phase_system::<Transparent2d>
|
(
|
||||||
.after(sort_phase_system::<Transparent2d>)
|
sort_phase_system::<Transparent2d>.in_set(RenderSet::PhaseSort),
|
||||||
.in_set(RenderSet::PhaseSort),
|
batch_phase_system::<Transparent2d>
|
||||||
));
|
.after(sort_phase_system::<Transparent2d>)
|
||||||
|
.in_set(RenderSet::PhaseSort),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
let pass_node_2d = MainPass2dNode::new(&mut render_app.world);
|
let pass_node_2d = MainPass2dNode::new(&mut render_app.world);
|
||||||
let tonemapping = TonemappingNode::new(&mut render_app.world);
|
let tonemapping = TonemappingNode::new(&mut render_app.world);
|
||||||
|
|
|
@ -23,7 +23,7 @@ use std::cmp::Reverse;
|
||||||
pub use camera_3d::*;
|
pub use camera_3d::*;
|
||||||
pub use main_pass_3d_node::*;
|
pub use main_pass_3d_node::*;
|
||||||
|
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
camera::{Camera, ExtractedCamera},
|
camera::{Camera, ExtractedCamera},
|
||||||
|
@ -41,7 +41,7 @@ use bevy_render::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::TextureCache,
|
texture::TextureCache,
|
||||||
view::ViewDepthTexture,
|
view::ViewDepthTexture,
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_utils::{FloatOrd, HashMap};
|
use bevy_utils::{FloatOrd, HashMap};
|
||||||
|
|
||||||
|
@ -68,15 +68,18 @@ impl Plugin for Core3dPlugin {
|
||||||
.init_resource::<DrawFunctions<Opaque3d>>()
|
.init_resource::<DrawFunctions<Opaque3d>>()
|
||||||
.init_resource::<DrawFunctions<AlphaMask3d>>()
|
.init_resource::<DrawFunctions<AlphaMask3d>>()
|
||||||
.init_resource::<DrawFunctions<Transparent3d>>()
|
.init_resource::<DrawFunctions<Transparent3d>>()
|
||||||
.add_systems((
|
.add_systems(ExtractSchedule, extract_core_3d_camera_phases)
|
||||||
extract_core_3d_camera_phases.in_schedule(ExtractSchedule),
|
.add_systems(
|
||||||
prepare_core_3d_depth_textures
|
Render,
|
||||||
.in_set(RenderSet::Prepare)
|
(
|
||||||
.after(bevy_render::view::prepare_windows),
|
prepare_core_3d_depth_textures
|
||||||
sort_phase_system::<Opaque3d>.in_set(RenderSet::PhaseSort),
|
.in_set(RenderSet::Prepare)
|
||||||
sort_phase_system::<AlphaMask3d>.in_set(RenderSet::PhaseSort),
|
.after(bevy_render::view::prepare_windows),
|
||||||
sort_phase_system::<Transparent3d>.in_set(RenderSet::PhaseSort),
|
sort_phase_system::<Opaque3d>.in_set(RenderSet::PhaseSort),
|
||||||
));
|
sort_phase_system::<AlphaMask3d>.in_set(RenderSet::PhaseSort),
|
||||||
|
sort_phase_system::<Transparent3d>.in_set(RenderSet::PhaseSort),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
let prepass_node = PrepassNode::new(&mut render_app.world);
|
let prepass_node = PrepassNode::new(&mut render_app.world);
|
||||||
let pass_node_3d = MainPass3dNode::new(&mut render_app.world);
|
let pass_node_3d = MainPass3dNode::new(&mut render_app.world);
|
||||||
|
|
|
@ -14,7 +14,7 @@ use bevy_render::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::BevyDefault,
|
texture::BevyDefault,
|
||||||
view::{ExtractedView, ViewTarget},
|
view::{ExtractedView, ViewTarget},
|
||||||
RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod node;
|
mod node;
|
||||||
|
@ -90,7 +90,7 @@ impl Plugin for FxaaPlugin {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<FxaaPipeline>()
|
.init_resource::<FxaaPipeline>()
|
||||||
.init_resource::<SpecializedRenderPipelines<FxaaPipeline>>()
|
.init_resource::<SpecializedRenderPipelines<FxaaPipeline>>()
|
||||||
.add_system(prepare_fxaa_pipelines.in_set(RenderSet::Prepare));
|
.add_systems(Render, prepare_fxaa_pipelines.in_set(RenderSet::Prepare));
|
||||||
|
|
||||||
{
|
{
|
||||||
let fxaa_node = FxaaNode::new(&mut render_app.world);
|
let fxaa_node = FxaaNode::new(&mut render_app.world);
|
||||||
|
|
|
@ -6,7 +6,7 @@ use bevy_render::{
|
||||||
render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext, SlotInfo, SlotType},
|
render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext, SlotInfo, SlotType},
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
view::{Msaa, ViewTarget},
|
view::{Msaa, ViewTarget},
|
||||||
RenderSet,
|
Render, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_render::{render_resource::*, RenderApp};
|
use bevy_render::{render_resource::*, RenderApp};
|
||||||
|
|
||||||
|
@ -20,7 +20,10 @@ impl Plugin for MsaaWritebackPlugin {
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
|
|
||||||
render_app.add_system(queue_msaa_writeback_pipelines.in_set(RenderSet::Queue));
|
render_app.add_systems(
|
||||||
|
Render,
|
||||||
|
queue_msaa_writeback_pipelines.in_set(RenderSet::Queue),
|
||||||
|
);
|
||||||
let msaa_writeback_2d = MsaaWritebackNode::new(&mut render_app.world);
|
let msaa_writeback_2d = MsaaWritebackNode::new(&mut render_app.world);
|
||||||
let msaa_writeback_3d = MsaaWritebackNode::new(&mut render_app.world);
|
let msaa_writeback_3d = MsaaWritebackNode::new(&mut render_app.world);
|
||||||
let mut graph = render_app.world.resource_mut::<RenderGraph>();
|
let mut graph = render_app.world.resource_mut::<RenderGraph>();
|
||||||
|
|
|
@ -10,7 +10,7 @@ use bevy_render::render_asset::RenderAssets;
|
||||||
use bevy_render::renderer::RenderDevice;
|
use bevy_render::renderer::RenderDevice;
|
||||||
use bevy_render::texture::{CompressedImageFormats, Image, ImageSampler, ImageType};
|
use bevy_render::texture::{CompressedImageFormats, Image, ImageSampler, ImageType};
|
||||||
use bevy_render::view::{ViewTarget, ViewUniform};
|
use bevy_render::view::{ViewTarget, ViewUniform};
|
||||||
use bevy_render::{render_resource::*, RenderApp, RenderSet};
|
use bevy_render::{render_resource::*, Render, RenderApp, RenderSet};
|
||||||
|
|
||||||
mod node;
|
mod node;
|
||||||
|
|
||||||
|
@ -94,7 +94,10 @@ impl Plugin for TonemappingPlugin {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<TonemappingPipeline>()
|
.init_resource::<TonemappingPipeline>()
|
||||||
.init_resource::<SpecializedRenderPipelines<TonemappingPipeline>>()
|
.init_resource::<SpecializedRenderPipelines<TonemappingPipeline>>()
|
||||||
.add_system(queue_view_tonemapping_pipelines.in_set(RenderSet::Queue));
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
queue_view_tonemapping_pipelines.in_set(RenderSet::Queue),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use bevy_app::prelude::*;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_render::camera::{CameraOutputMode, ExtractedCamera};
|
use bevy_render::camera::{CameraOutputMode, ExtractedCamera};
|
||||||
use bevy_render::view::ViewTarget;
|
use bevy_render::view::ViewTarget;
|
||||||
use bevy_render::{render_resource::*, RenderApp, RenderSet};
|
use bevy_render::{render_resource::*, Render, RenderApp, RenderSet};
|
||||||
|
|
||||||
mod node;
|
mod node;
|
||||||
|
|
||||||
|
@ -14,7 +14,10 @@ pub struct UpscalingPlugin;
|
||||||
impl Plugin for UpscalingPlugin {
|
impl Plugin for UpscalingPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app.add_system(queue_view_upscaling_pipelines.in_set(RenderSet::Queue));
|
render_app.add_systems(
|
||||||
|
Render,
|
||||||
|
queue_view_upscaling_pipelines.in_set(RenderSet::Queue),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ pub struct EntityCountDiagnosticsPlugin;
|
||||||
|
|
||||||
impl Plugin for EntityCountDiagnosticsPlugin {
|
impl Plugin for EntityCountDiagnosticsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_startup_system(Self::setup_system)
|
app.add_systems(Startup, Self::setup_system)
|
||||||
.add_system(Self::diagnostic_system);
|
.add_systems(Update, Self::diagnostic_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@ pub struct FrameTimeDiagnosticsPlugin;
|
||||||
|
|
||||||
impl Plugin for FrameTimeDiagnosticsPlugin {
|
impl Plugin for FrameTimeDiagnosticsPlugin {
|
||||||
fn build(&self, app: &mut bevy_app::App) {
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
app.add_startup_system(Self::setup_system)
|
app.add_systems(Startup, Self::setup_system)
|
||||||
.add_system(Self::diagnostic_system);
|
.add_systems(Update, Self::diagnostic_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,10 @@ pub struct DiagnosticsPlugin;
|
||||||
|
|
||||||
impl Plugin for DiagnosticsPlugin {
|
impl Plugin for DiagnosticsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<Diagnostics>()
|
app.init_resource::<Diagnostics>().add_systems(
|
||||||
.add_startup_system(system_information_diagnostics_plugin::internal::log_system_info);
|
Startup,
|
||||||
|
system_information_diagnostics_plugin::internal::log_system_info,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,9 +37,9 @@ impl Plugin for LogDiagnosticsPlugin {
|
||||||
});
|
});
|
||||||
|
|
||||||
if self.debug {
|
if self.debug {
|
||||||
app.add_system(Self::log_diagnostics_debug_system.in_base_set(CoreSet::PostUpdate));
|
app.add_systems(PostUpdate, Self::log_diagnostics_debug_system);
|
||||||
} else {
|
} else {
|
||||||
app.add_system(Self::log_diagnostics_system.in_base_set(CoreSet::PostUpdate));
|
app.add_systems(PostUpdate, Self::log_diagnostics_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ use bevy_app::prelude::*;
|
||||||
pub struct SystemInformationDiagnosticsPlugin;
|
pub struct SystemInformationDiagnosticsPlugin;
|
||||||
impl Plugin for SystemInformationDiagnosticsPlugin {
|
impl Plugin for SystemInformationDiagnosticsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_startup_system(internal::setup_system)
|
app.add_systems(Startup, internal::setup_system)
|
||||||
.add_system(internal::diagnostic_system);
|
.add_systems(Update, internal::diagnostic_system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ fn main() {
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
|
|
||||||
// Add our system to the schedule
|
// Add our system to the schedule
|
||||||
schedule.add_system(movement);
|
schedule.add_systems(movement);
|
||||||
|
|
||||||
// Run the schedule once. If your app has a "loop", you would run this once per loop
|
// Run the schedule once. If your app has a "loop", you would run this once per loop
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy_ecs::{prelude::*, schedule::IntoSystemConfig};
|
use bevy_ecs::prelude::*;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
||||||
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct FlushEvents;
|
pub struct FlushEvents;
|
||||||
|
|
||||||
schedule.add_system(Events::<MyEvent>::update_system.in_set(FlushEvents));
|
schedule.add_systems(Events::<MyEvent>::update_system.in_set(FlushEvents));
|
||||||
|
|
||||||
// Add systems sending and receiving events after the events are flushed.
|
// Add systems sending and receiving events after the events are flushed.
|
||||||
schedule.add_systems((
|
schedule.add_systems((
|
||||||
|
|
|
@ -469,7 +469,7 @@ pub fn derive_schedule_label(input: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derive macro generating an impl of the trait `SystemSet`.
|
/// Derive macro generating an impl of the trait `SystemSet`.
|
||||||
#[proc_macro_derive(SystemSet, attributes(system_set))]
|
#[proc_macro_derive(SystemSet)]
|
||||||
pub fn derive_system_set(input: TokenStream) -> TokenStream {
|
pub fn derive_system_set(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
let mut trait_path = bevy_ecs_path();
|
let mut trait_path = bevy_ecs_path();
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::{format_ident, quote, ToTokens};
|
use quote::quote;
|
||||||
use syn::parse::{Parse, ParseStream};
|
|
||||||
|
|
||||||
pub static SYSTEM_SET_ATTRIBUTE_NAME: &str = "system_set";
|
|
||||||
pub static BASE_ATTRIBUTE_NAME: &str = "base";
|
|
||||||
|
|
||||||
/// Derive a set trait
|
/// Derive a set trait
|
||||||
///
|
///
|
||||||
|
@ -12,55 +8,8 @@ pub static BASE_ATTRIBUTE_NAME: &str = "base";
|
||||||
/// - `input`: The [`syn::DeriveInput`] for the struct that we want to derive the set trait for
|
/// - `input`: The [`syn::DeriveInput`] for the struct that we want to derive the set trait for
|
||||||
/// - `trait_path`: The [`syn::Path`] to the set trait
|
/// - `trait_path`: The [`syn::Path`] to the set trait
|
||||||
pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream {
|
pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStream {
|
||||||
let mut base_trait_path = trait_path.clone();
|
|
||||||
let ident = &mut base_trait_path.segments.last_mut().unwrap().ident;
|
|
||||||
*ident = format_ident!("Base{ident}");
|
|
||||||
|
|
||||||
let mut free_trait_path = trait_path.clone();
|
|
||||||
let ident = &mut free_trait_path.segments.last_mut().unwrap().ident;
|
|
||||||
*ident = format_ident!("Free{ident}");
|
|
||||||
|
|
||||||
let ident = input.ident;
|
let ident = input.ident;
|
||||||
|
|
||||||
let mut is_base = false;
|
|
||||||
for attr in &input.attrs {
|
|
||||||
if !attr
|
|
||||||
.path
|
|
||||||
.get_ident()
|
|
||||||
.map_or(false, |ident| ident == SYSTEM_SET_ATTRIBUTE_NAME)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.parse_args_with(|input: ParseStream| {
|
|
||||||
let meta = input.parse_terminated::<syn::Meta, syn::token::Comma>(syn::Meta::parse)?;
|
|
||||||
for meta in meta {
|
|
||||||
let ident = meta.path().get_ident().unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"Unrecognized attribute: `{}`",
|
|
||||||
meta.path().to_token_stream()
|
|
||||||
)
|
|
||||||
});
|
|
||||||
if ident == BASE_ATTRIBUTE_NAME {
|
|
||||||
if let syn::Meta::Path(_) = meta {
|
|
||||||
is_base = true;
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"The `{BASE_ATTRIBUTE_NAME}` attribute is expected to have no value or arguments",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Unrecognized attribute: `{}`",
|
|
||||||
meta.path().to_token_stream()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|_| panic!("Invalid `{SYSTEM_SET_ATTRIBUTE_NAME}` attribute format"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||||
let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
|
let mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
|
||||||
where_token: Default::default(),
|
where_token: Default::default(),
|
||||||
|
@ -73,28 +22,12 @@ pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStrea
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let marker_impl = if is_base {
|
|
||||||
quote! {
|
|
||||||
impl #impl_generics #base_trait_path for #ident #ty_generics #where_clause {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
impl #impl_generics #free_trait_path for #ident #ty_generics #where_clause {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(quote! {
|
(quote! {
|
||||||
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
|
impl #impl_generics #trait_path for #ident #ty_generics #where_clause {
|
||||||
fn is_base(&self) -> bool {
|
|
||||||
#is_base
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dyn_clone(&self) -> std::boxed::Box<dyn #trait_path> {
|
fn dyn_clone(&self) -> std::boxed::Box<dyn #trait_path> {
|
||||||
std::boxed::Box::new(std::clone::Clone::clone(self))
|
std::boxed::Box::new(std::clone::Clone::clone(self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#marker_impl
|
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -939,7 +939,7 @@ mod tests {
|
||||||
world.send_event(TestEvent { i: 4 });
|
world.send_event(TestEvent { i: 4 });
|
||||||
|
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
schedule.add_system(|mut events: EventReader<TestEvent>| {
|
schedule.add_systems(|mut events: EventReader<TestEvent>| {
|
||||||
let mut iter = events.iter();
|
let mut iter = events.iter();
|
||||||
|
|
||||||
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
|
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
|
||||||
|
|
|
@ -39,9 +39,8 @@ pub mod prelude {
|
||||||
removal_detection::RemovedComponents,
|
removal_detection::RemovedComponents,
|
||||||
schedule::{
|
schedule::{
|
||||||
apply_state_transition, apply_system_buffers, common_conditions::*, Condition,
|
apply_state_transition, apply_system_buffers, common_conditions::*, Condition,
|
||||||
IntoSystemConfig, IntoSystemConfigs, IntoSystemSet, IntoSystemSetConfig,
|
IntoSystemConfigs, IntoSystemSet, IntoSystemSetConfig, IntoSystemSetConfigs, NextState,
|
||||||
IntoSystemSetConfigs, NextState, OnEnter, OnExit, OnTransition, OnUpdate, Schedule,
|
OnEnter, OnExit, OnTransition, OnUpdate, Schedule, Schedules, State, States, SystemSet,
|
||||||
Schedules, State, States, SystemSet,
|
|
||||||
},
|
},
|
||||||
system::{
|
system::{
|
||||||
adapter as system_adapter,
|
adapter as system_adapter,
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub trait Condition<Marker>: sealed::Condition<Marker> {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # fn my_system() {}
|
/// # fn my_system() {}
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // The `resource_equals` run condition will panic since we don't initialize `R`,
|
/// // The `resource_equals` run condition will panic since we don't initialize `R`,
|
||||||
/// // just like if we used `Res<R>` in a system.
|
/// // just like if we used `Res<R>` in a system.
|
||||||
/// my_system.run_if(resource_equals(R(0))),
|
/// my_system.run_if(resource_equals(R(0))),
|
||||||
|
@ -48,7 +48,7 @@ pub trait Condition<Marker>: sealed::Condition<Marker> {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # fn my_system() {}
|
/// # fn my_system() {}
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_equals` will only get run if the resource `R` exists.
|
/// // `resource_equals` will only get run if the resource `R` exists.
|
||||||
/// my_system.run_if(resource_exists::<R>().and_then(resource_equals(R(0)))),
|
/// my_system.run_if(resource_exists::<R>().and_then(resource_equals(R(0)))),
|
||||||
/// );
|
/// );
|
||||||
|
@ -86,7 +86,7 @@ pub trait Condition<Marker>: sealed::Condition<Marker> {
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # #[derive(Resource)] struct C(bool);
|
/// # #[derive(Resource)] struct C(bool);
|
||||||
/// # fn my_system(mut c: ResMut<C>) { c.0 = true; }
|
/// # fn my_system(mut c: ResMut<C>) { c.0 = true; }
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // Only run the system if either `A` or `B` exist.
|
/// // Only run the system if either `A` or `B` exist.
|
||||||
/// my_system.run_if(resource_exists::<A>().or_else(resource_exists::<B>())),
|
/// my_system.run_if(resource_exists::<A>().or_else(resource_exists::<B>())),
|
||||||
/// );
|
/// );
|
||||||
|
@ -159,7 +159,7 @@ pub mod common_conditions {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `run_once` will only return true the first time it's evaluated
|
/// // `run_once` will only return true the first time it's evaluated
|
||||||
/// my_system.run_if(run_once()),
|
/// my_system.run_if(run_once()),
|
||||||
/// );
|
/// );
|
||||||
|
@ -199,7 +199,7 @@ pub mod common_conditions {
|
||||||
/// # struct Counter(u8);
|
/// # struct Counter(u8);
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_exsists` will only return true if the given resource exsists in the world
|
/// // `resource_exsists` will only return true if the given resource exsists in the world
|
||||||
/// my_system.run_if(resource_exists::<Counter>()),
|
/// my_system.run_if(resource_exists::<Counter>()),
|
||||||
/// );
|
/// );
|
||||||
|
@ -239,7 +239,7 @@ pub mod common_conditions {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_equals` will only return true if the given resource equals the given value
|
/// // `resource_equals` will only return true if the given resource equals the given value
|
||||||
/// my_system.run_if(resource_equals(Counter(0))),
|
/// my_system.run_if(resource_equals(Counter(0))),
|
||||||
/// );
|
/// );
|
||||||
|
@ -276,7 +276,7 @@ pub mod common_conditions {
|
||||||
/// # struct Counter(u8);
|
/// # struct Counter(u8);
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_exists_and_equals` will only return true
|
/// // `resource_exists_and_equals` will only return true
|
||||||
/// // if the given resource exsists and equals the given value
|
/// // if the given resource exsists and equals the given value
|
||||||
/// my_system.run_if(resource_exists_and_equals(Counter(0))),
|
/// my_system.run_if(resource_exists_and_equals(Counter(0))),
|
||||||
|
@ -319,7 +319,7 @@ pub mod common_conditions {
|
||||||
/// # struct Counter(u8);
|
/// # struct Counter(u8);
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_added` will only return true if the
|
/// // `resource_added` will only return true if the
|
||||||
/// // given resource was just added
|
/// // given resource was just added
|
||||||
/// my_system.run_if(resource_added::<Counter>()),
|
/// my_system.run_if(resource_added::<Counter>()),
|
||||||
|
@ -370,7 +370,7 @@ pub mod common_conditions {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_changed` will only return true if the
|
/// // `resource_changed` will only return true if the
|
||||||
/// // given resource was just changed (or added)
|
/// // given resource was just changed (or added)
|
||||||
/// my_system.run_if(
|
/// my_system.run_if(
|
||||||
|
@ -423,7 +423,7 @@ pub mod common_conditions {
|
||||||
/// # struct Counter(u8);
|
/// # struct Counter(u8);
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_exists_and_changed` will only return true if the
|
/// // `resource_exists_and_changed` will only return true if the
|
||||||
/// // given resource exsists and was just changed (or added)
|
/// // given resource exsists and was just changed (or added)
|
||||||
/// my_system.run_if(
|
/// my_system.run_if(
|
||||||
|
@ -485,7 +485,7 @@ pub mod common_conditions {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_changed_or_removed` will only return true if the
|
/// // `resource_changed_or_removed` will only return true if the
|
||||||
/// // given resource was just changed or removed (or added)
|
/// // given resource was just changed or removed (or added)
|
||||||
/// my_system.run_if(
|
/// my_system.run_if(
|
||||||
|
@ -555,7 +555,7 @@ pub mod common_conditions {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `resource_removed` will only return true if the
|
/// // `resource_removed` will only return true if the
|
||||||
/// // given resource was just removed
|
/// // given resource was just removed
|
||||||
/// my_system.run_if(resource_removed::<MyResource>()),
|
/// my_system.run_if(resource_removed::<MyResource>()),
|
||||||
|
@ -617,7 +617,7 @@ pub mod common_conditions {
|
||||||
/// Paused,
|
/// Paused,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `state_exists` will only return true if the
|
/// // `state_exists` will only return true if the
|
||||||
/// // given state exsists
|
/// // given state exsists
|
||||||
/// my_system.run_if(state_exists::<GameState>()),
|
/// my_system.run_if(state_exists::<GameState>()),
|
||||||
|
@ -784,7 +784,7 @@ pub mod common_conditions {
|
||||||
///
|
///
|
||||||
/// world.init_resource::<State<GameState>>();
|
/// world.init_resource::<State<GameState>>();
|
||||||
///
|
///
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `state_changed` will only return true if the
|
/// // `state_changed` will only return true if the
|
||||||
/// // given states value has just been updated or
|
/// // given states value has just been updated or
|
||||||
/// // the state has just been added
|
/// // the state has just been added
|
||||||
|
@ -826,9 +826,9 @@ pub mod common_conditions {
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// # world.init_resource::<Events<MyEvent>>();
|
/// # world.init_resource::<Events<MyEvent>>();
|
||||||
/// # app.add_system(Events::<MyEvent>::update_system.before(my_system));
|
/// # app.add_systems(Events::<MyEvent>::update_system.before(my_system));
|
||||||
///
|
///
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// my_system.run_if(on_event::<MyEvent>()),
|
/// my_system.run_if(on_event::<MyEvent>()),
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
|
@ -868,7 +868,7 @@ pub mod common_conditions {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// my_system.run_if(any_with_component::<MyComponent>()),
|
/// my_system.run_if(any_with_component::<MyComponent>()),
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
|
@ -904,7 +904,7 @@ pub mod common_conditions {
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// app.add_system(
|
/// app.add_systems(
|
||||||
/// // `not` will inverse any condition you pass in.
|
/// // `not` will inverse any condition you pass in.
|
||||||
/// // Since the condition we choose always returns true
|
/// // Since the condition we choose always returns true
|
||||||
/// // this system will never run
|
/// // this system will never run
|
||||||
|
@ -1073,15 +1073,11 @@ where
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{common_conditions::*, Condition};
|
use super::{common_conditions::*, Condition};
|
||||||
use crate as bevy_ecs;
|
use crate as bevy_ecs;
|
||||||
use crate::{
|
use crate::component::Component;
|
||||||
change_detection::ResMut,
|
use crate::schedule::IntoSystemConfigs;
|
||||||
component::Component,
|
use crate::schedule::{common_conditions::not, State, States};
|
||||||
schedule::{
|
use crate::system::Local;
|
||||||
common_conditions::not, IntoSystemConfig, IntoSystemConfigs, Schedule, State, States,
|
use crate::{change_detection::ResMut, schedule::Schedule, world::World};
|
||||||
},
|
|
||||||
system::Local,
|
|
||||||
world::World,
|
|
||||||
};
|
|
||||||
use bevy_ecs_macros::Resource;
|
use bevy_ecs_macros::Resource;
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
|
@ -1103,7 +1099,7 @@ mod tests {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
|
|
||||||
// Run every other cycle
|
// Run every other cycle
|
||||||
schedule.add_system(increment_counter.run_if(every_other_time));
|
schedule.add_systems(increment_counter.run_if(every_other_time));
|
||||||
|
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
@ -1113,7 +1109,7 @@ mod tests {
|
||||||
assert_eq!(world.resource::<Counter>().0, 2);
|
assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
|
|
||||||
// Run every other cycle oppsite to the last one
|
// Run every other cycle oppsite to the last one
|
||||||
schedule.add_system(increment_counter.run_if(not(every_other_time)));
|
schedule.add_systems(increment_counter.run_if(not(every_other_time)));
|
||||||
|
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
@ -1130,9 +1126,9 @@ mod tests {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
|
|
||||||
// Always run
|
// Always run
|
||||||
schedule.add_system(increment_counter.run_if(every_other_time.or_else(|| true)));
|
schedule.add_systems(increment_counter.run_if(every_other_time.or_else(|| true)));
|
||||||
// Run every other cycle
|
// Run every other cycle
|
||||||
schedule.add_system(increment_counter.run_if(every_other_time.and_then(|| true)));
|
schedule.add_systems(increment_counter.run_if(every_other_time.and_then(|| true)));
|
||||||
|
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
assert_eq!(world.resource::<Counter>().0, 2);
|
assert_eq!(world.resource::<Counter>().0, 2);
|
||||||
|
@ -1147,9 +1143,9 @@ mod tests {
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
|
|
||||||
// Run every other cycle
|
// Run every other cycle
|
||||||
schedule.add_system(increment_counter.run_if(every_other_time).run_if(|| true));
|
schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| true));
|
||||||
// Never run
|
// Never run
|
||||||
schedule.add_system(increment_counter.run_if(every_other_time).run_if(|| false));
|
schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| false));
|
||||||
|
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
assert_eq!(world.resource::<Counter>().0, 1);
|
assert_eq!(world.resource::<Counter>().0, 1);
|
||||||
|
@ -1166,7 +1162,7 @@ mod tests {
|
||||||
|
|
||||||
// This should never run, if multiple run conditions worked
|
// This should never run, if multiple run conditions worked
|
||||||
// like an OR condition then it would always run
|
// like an OR condition then it would always run
|
||||||
schedule.add_system(
|
schedule.add_systems(
|
||||||
increment_counter
|
increment_counter
|
||||||
.run_if(every_other_time)
|
.run_if(every_other_time)
|
||||||
.run_if(not(every_other_time)),
|
.run_if(not(every_other_time)),
|
||||||
|
|
|
@ -5,57 +5,11 @@ use crate::{
|
||||||
condition::{BoxedCondition, Condition},
|
condition::{BoxedCondition, Condition},
|
||||||
graph_utils::{Ambiguity, Dependency, DependencyKind, GraphInfo},
|
graph_utils::{Ambiguity, Dependency, DependencyKind, GraphInfo},
|
||||||
set::{BoxedSystemSet, IntoSystemSet, SystemSet},
|
set::{BoxedSystemSet, IntoSystemSet, SystemSet},
|
||||||
|
ScheduleLabel,
|
||||||
},
|
},
|
||||||
system::{BoxedSystem, IntoSystem, System},
|
system::{BoxedSystem, IntoSystem, System},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{BaseSystemSet, FreeSystemSet};
|
|
||||||
|
|
||||||
/// A [`SystemSet`] with scheduling metadata.
|
|
||||||
pub struct SystemSetConfig {
|
|
||||||
pub(super) set: BoxedSystemSet,
|
|
||||||
pub(super) graph_info: GraphInfo,
|
|
||||||
pub(super) conditions: Vec<BoxedCondition>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SystemSetConfig {
|
|
||||||
fn new(set: BoxedSystemSet) -> Self {
|
|
||||||
// system type sets are automatically populated
|
|
||||||
// to avoid unintentionally broad changes, they cannot be configured
|
|
||||||
assert!(
|
|
||||||
set.system_type().is_none(),
|
|
||||||
"configuring system type sets is not allowed"
|
|
||||||
);
|
|
||||||
|
|
||||||
Self {
|
|
||||||
set,
|
|
||||||
graph_info: GraphInfo::system_set(),
|
|
||||||
conditions: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`System`] with scheduling metadata.
|
|
||||||
pub struct SystemConfig {
|
|
||||||
pub(super) system: BoxedSystem,
|
|
||||||
pub(super) graph_info: GraphInfo,
|
|
||||||
pub(super) conditions: Vec<BoxedCondition>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SystemConfig {
|
|
||||||
fn new(system: BoxedSystem) -> Self {
|
|
||||||
// include system in its default sets
|
|
||||||
let sets = system.default_system_sets().into_iter().collect();
|
|
||||||
let mut graph_info = GraphInfo::system();
|
|
||||||
graph_info.sets = sets;
|
|
||||||
Self {
|
|
||||||
system,
|
|
||||||
graph_info,
|
|
||||||
conditions: Vec::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_condition<M>(condition: impl Condition<M>) -> BoxedCondition {
|
fn new_condition<M>(condition: impl Condition<M>) -> BoxedCondition {
|
||||||
let condition_system = IntoSystem::into_system(condition);
|
let condition_system = IntoSystem::into_system(condition);
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -79,6 +33,370 @@ fn ambiguous_with(graph_info: &mut GraphInfo, set: BoxedSystemSet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Marker, F> IntoSystemConfigs<Marker> for F
|
||||||
|
where
|
||||||
|
F: IntoSystem<(), (), Marker>,
|
||||||
|
{
|
||||||
|
fn into_configs(self) -> SystemConfigs {
|
||||||
|
SystemConfigs::new_system(Box::new(IntoSystem::into_system(self)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoSystemConfigs<()> for BoxedSystem<(), ()> {
|
||||||
|
fn into_configs(self) -> SystemConfigs {
|
||||||
|
SystemConfigs::new_system(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SystemConfig {
|
||||||
|
pub(crate) system: BoxedSystem,
|
||||||
|
pub(crate) graph_info: GraphInfo,
|
||||||
|
pub(crate) conditions: Vec<BoxedCondition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A collection of [`SystemConfig`].
|
||||||
|
pub enum SystemConfigs {
|
||||||
|
SystemConfig(SystemConfig),
|
||||||
|
Configs {
|
||||||
|
configs: Vec<SystemConfigs>,
|
||||||
|
/// If `true`, adds `before -> after` ordering constraints between the successive elements.
|
||||||
|
chained: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemConfigs {
|
||||||
|
fn new_system(system: BoxedSystem) -> Self {
|
||||||
|
// include system in its default sets
|
||||||
|
let sets = system.default_system_sets().into_iter().collect();
|
||||||
|
Self::SystemConfig(SystemConfig {
|
||||||
|
system,
|
||||||
|
graph_info: GraphInfo {
|
||||||
|
sets,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
conditions: Vec::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_set_inner(&mut self, set: BoxedSystemSet) {
|
||||||
|
match self {
|
||||||
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
config.graph_info.sets.push(set);
|
||||||
|
}
|
||||||
|
SystemConfigs::Configs { configs, .. } => {
|
||||||
|
for config in configs {
|
||||||
|
config.in_set_inner(set.dyn_clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before_inner(&mut self, set: BoxedSystemSet) {
|
||||||
|
match self {
|
||||||
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
config
|
||||||
|
.graph_info
|
||||||
|
.dependencies
|
||||||
|
.push(Dependency::new(DependencyKind::Before, set));
|
||||||
|
}
|
||||||
|
SystemConfigs::Configs { configs, .. } => {
|
||||||
|
for config in configs {
|
||||||
|
config.before_inner(set.dyn_clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after_inner(&mut self, set: BoxedSystemSet) {
|
||||||
|
match self {
|
||||||
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
config
|
||||||
|
.graph_info
|
||||||
|
.dependencies
|
||||||
|
.push(Dependency::new(DependencyKind::After, set));
|
||||||
|
}
|
||||||
|
SystemConfigs::Configs { configs, .. } => {
|
||||||
|
for config in configs {
|
||||||
|
config.after_inner(set.dyn_clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn distributive_run_if_inner<M>(&mut self, condition: impl Condition<M> + Clone) {
|
||||||
|
match self {
|
||||||
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
config.conditions.push(new_condition(condition));
|
||||||
|
}
|
||||||
|
SystemConfigs::Configs { configs, .. } => {
|
||||||
|
for config in configs {
|
||||||
|
config.distributive_run_if_inner(condition.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ambiguous_with_inner(&mut self, set: BoxedSystemSet) {
|
||||||
|
match self {
|
||||||
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
ambiguous_with(&mut config.graph_info, set);
|
||||||
|
}
|
||||||
|
SystemConfigs::Configs { configs, .. } => {
|
||||||
|
for config in configs {
|
||||||
|
config.ambiguous_with_inner(set.dyn_clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ambiguous_with_all_inner(&mut self) {
|
||||||
|
match self {
|
||||||
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
config.graph_info.ambiguous_with = Ambiguity::IgnoreAll;
|
||||||
|
}
|
||||||
|
SystemConfigs::Configs { configs, .. } => {
|
||||||
|
for config in configs {
|
||||||
|
config.ambiguous_with_all_inner();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_if_inner(&mut self, condition: BoxedCondition) {
|
||||||
|
match self {
|
||||||
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
config.conditions.push(condition);
|
||||||
|
}
|
||||||
|
SystemConfigs::Configs { .. } => {
|
||||||
|
todo!("run_if is not implemented for groups of systems yet")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Types that can convert into a [`SystemConfigs`].
|
||||||
|
pub trait IntoSystemConfigs<Marker>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
/// Convert into a [`SystemConfigs`].
|
||||||
|
#[doc(hidden)]
|
||||||
|
fn into_configs(self) -> SystemConfigs;
|
||||||
|
|
||||||
|
/// Add these systems to the provided `set`.
|
||||||
|
#[track_caller]
|
||||||
|
fn in_set(self, set: impl SystemSet) -> SystemConfigs {
|
||||||
|
self.into_configs().in_set(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run before all systems in `set`.
|
||||||
|
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
|
||||||
|
self.into_configs().before(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run after all systems in `set`.
|
||||||
|
fn after<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
|
||||||
|
self.into_configs().after(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a run condition to each contained system.
|
||||||
|
///
|
||||||
|
/// Each system will receive its own clone of the [`Condition`] and will only run
|
||||||
|
/// if the `Condition` is true.
|
||||||
|
///
|
||||||
|
/// Each individual condition will be evaluated at most once (per schedule run),
|
||||||
|
/// right before the corresponding system prepares to run.
|
||||||
|
///
|
||||||
|
/// This is equivalent to calling [`run_if`](IntoSystemConfigs::run_if) on each individual
|
||||||
|
/// system, as shown below:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
/// # let mut app = Schedule::new();
|
||||||
|
/// # fn a() {}
|
||||||
|
/// # fn b() {}
|
||||||
|
/// # fn condition() -> bool { true }
|
||||||
|
/// app.add_systems((a, b).distributive_run_if(condition));
|
||||||
|
/// app.add_systems((a.run_if(condition), b.run_if(condition)));
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// Because the conditions are evaluated separately for each system, there is no guarantee
|
||||||
|
/// that all evaluations in a single schedule run will yield the same result. If another
|
||||||
|
/// system is run inbetween two evaluations it could cause the result of the condition to change.
|
||||||
|
///
|
||||||
|
/// Use [`run_if`](IntoSystemSetConfig::run_if) on a [`SystemSet`] if you want to make sure
|
||||||
|
/// that either all or none of the systems are run, or you don't want to evaluate the run
|
||||||
|
/// condition for each contained system separately.
|
||||||
|
fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> SystemConfigs {
|
||||||
|
self.into_configs().distributive_run_if(condition)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the systems only if the [`Condition`] is `true`.
|
||||||
|
///
|
||||||
|
/// The `Condition` will be evaluated at most once (per schedule run),
|
||||||
|
/// the first time a system in this set prepares to run.
|
||||||
|
fn run_if<M>(self, condition: impl Condition<M>) -> SystemConfigs {
|
||||||
|
self.into_configs().run_if(condition)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Suppress warnings and errors that would result from these systems having ambiguities
|
||||||
|
/// (conflicting access but indeterminate order) with systems in `set`.
|
||||||
|
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
|
||||||
|
self.into_configs().ambiguous_with(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Suppress warnings and errors that would result from these systems having ambiguities
|
||||||
|
/// (conflicting access but indeterminate order) with any other system.
|
||||||
|
fn ambiguous_with_all(self) -> SystemConfigs {
|
||||||
|
self.into_configs().ambiguous_with_all()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Treat this collection as a sequence of systems.
|
||||||
|
///
|
||||||
|
/// Ordering constraints will be applied between the successive elements.
|
||||||
|
fn chain(self) -> SystemConfigs {
|
||||||
|
self.into_configs().chain()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This used to add the system to `CoreSchedule::Startup`.
|
||||||
|
/// This was a shorthand for `self.in_schedule(CoreSchedule::Startup)`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Always panics. Please migrate to the new `App::add_systems` with the `Startup` schedule:
|
||||||
|
/// Ex: `app.add_system(foo.on_startup())` -> `app.add_systems(Startup, foo)`
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.11.0",
|
||||||
|
note = "`app.add_system(foo.on_startup())` has been deprecated in favor of `app.add_systems(Startup, foo)`. Please migrate to that API."
|
||||||
|
)]
|
||||||
|
fn on_startup(self) -> SystemConfigs {
|
||||||
|
panic!("`app.add_system(foo.on_startup())` has been deprecated in favor of `app.add_systems(Startup, foo)`. Please migrate to that API.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This used to add the system to the provided `schedule`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Always panics. Please migrate to the new `App::add_systems`:
|
||||||
|
/// Ex: `app.add_system(foo.in_schedule(SomeSchedule))` -> `app.add_systems(SomeSchedule, foo)`
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.11.0",
|
||||||
|
note = "`app.add_system(foo.in_schedule(SomeSchedule))` has been deprecated in favor of `app.add_systems(SomeSchedule, foo)`. Please migrate to that API."
|
||||||
|
)]
|
||||||
|
fn in_schedule(self, _schedule: impl ScheduleLabel) -> SystemConfigs {
|
||||||
|
panic!("`app.add_system(foo.in_schedule(SomeSchedule))` has been deprecated in favor of `app.add_systems(SomeSchedule, foo)`. Please migrate to that API.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoSystemConfigs<()> for SystemConfigs {
|
||||||
|
fn into_configs(self) -> Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn in_set(mut self, set: impl SystemSet) -> Self {
|
||||||
|
assert!(
|
||||||
|
set.system_type().is_none(),
|
||||||
|
"adding arbitrary systems to a system type set is not allowed"
|
||||||
|
);
|
||||||
|
|
||||||
|
self.in_set_inner(set.dyn_clone());
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
||||||
|
let set = set.into_system_set();
|
||||||
|
self.before_inner(set.dyn_clone());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
||||||
|
let set = set.into_system_set();
|
||||||
|
self.after_inner(set.dyn_clone());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn distributive_run_if<M>(mut self, condition: impl Condition<M> + Clone) -> SystemConfigs {
|
||||||
|
self.distributive_run_if_inner(condition);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
||||||
|
let set = set.into_system_set();
|
||||||
|
self.ambiguous_with_inner(set.dyn_clone());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ambiguous_with_all(mut self) -> Self {
|
||||||
|
self.ambiguous_with_all_inner();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_if<M>(mut self, condition: impl Condition<M>) -> SystemConfigs {
|
||||||
|
self.run_if_inner(new_condition(condition));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chain(mut self) -> Self {
|
||||||
|
match &mut self {
|
||||||
|
SystemConfigs::SystemConfig(_) => { /* no op */ }
|
||||||
|
SystemConfigs::Configs { chained, .. } => {
|
||||||
|
*chained = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SystemConfigTupleMarker;
|
||||||
|
|
||||||
|
macro_rules! impl_system_collection {
|
||||||
|
($(($param: ident, $sys: ident)),*) => {
|
||||||
|
impl<$($param, $sys),*> IntoSystemConfigs<(SystemConfigTupleMarker, $($param,)*)> for ($($sys,)*)
|
||||||
|
where
|
||||||
|
$($sys: IntoSystemConfigs<$param>),*
|
||||||
|
{
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn into_configs(self) -> SystemConfigs {
|
||||||
|
let ($($sys,)*) = self;
|
||||||
|
SystemConfigs::Configs {
|
||||||
|
configs: vec![$($sys.into_configs(),)*],
|
||||||
|
chained: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
all_tuples!(impl_system_collection, 1, 20, P, S);
|
||||||
|
|
||||||
|
/// A [`SystemSet`] with scheduling metadata.
|
||||||
|
pub struct SystemSetConfig {
|
||||||
|
pub(super) set: BoxedSystemSet,
|
||||||
|
pub(super) graph_info: GraphInfo,
|
||||||
|
pub(super) conditions: Vec<BoxedCondition>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemSetConfig {
|
||||||
|
fn new(set: BoxedSystemSet) -> Self {
|
||||||
|
// system type sets are automatically populated
|
||||||
|
// to avoid unintentionally broad changes, they cannot be configured
|
||||||
|
assert!(
|
||||||
|
set.system_type().is_none(),
|
||||||
|
"configuring system type sets is not allowed"
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
set,
|
||||||
|
graph_info: GraphInfo::default(),
|
||||||
|
conditions: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Types that can be converted into a [`SystemSetConfig`].
|
/// Types that can be converted into a [`SystemSetConfig`].
|
||||||
///
|
///
|
||||||
/// This has been implemented for all types that implement [`SystemSet`] and boxed trait objects.
|
/// This has been implemented for all types that implement [`SystemSet`] and boxed trait objects.
|
||||||
|
@ -88,18 +406,9 @@ pub trait IntoSystemSetConfig: Sized {
|
||||||
fn into_config(self) -> SystemSetConfig;
|
fn into_config(self) -> SystemSetConfig;
|
||||||
/// Add to the provided `set`.
|
/// Add to the provided `set`.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfig {
|
fn in_set(self, set: impl SystemSet) -> SystemSetConfig {
|
||||||
self.into_config().in_set(set)
|
self.into_config().in_set(set)
|
||||||
}
|
}
|
||||||
/// Add to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`].
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(self, set: impl BaseSystemSet) -> SystemSetConfig {
|
|
||||||
self.into_config().in_base_set(set)
|
|
||||||
}
|
|
||||||
/// Add this set to the schedules's default base set.
|
|
||||||
fn in_default_base_set(self) -> SystemSetConfig {
|
|
||||||
self.into_config().in_default_base_set()
|
|
||||||
}
|
|
||||||
/// Run before all systems in `set`.
|
/// Run before all systems in `set`.
|
||||||
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfig {
|
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfig {
|
||||||
self.into_config().before(set)
|
self.into_config().before(set)
|
||||||
|
@ -125,6 +434,35 @@ pub trait IntoSystemSetConfig: Sized {
|
||||||
fn ambiguous_with_all(self) -> SystemSetConfig {
|
fn ambiguous_with_all(self) -> SystemSetConfig {
|
||||||
self.into_config().ambiguous_with_all()
|
self.into_config().ambiguous_with_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This used to configure the set in the `CoreSchedule::Startup` schedule.
|
||||||
|
/// This was a shorthand for `self.in_schedule(CoreSchedule::Startup)`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Always panics. Please migrate to the new `App::configure_set` with the `Startup` schedule:
|
||||||
|
/// Ex: `app.configure_set(MySet.on_startup())` -> `app.configure_set(Startup, MySet)`
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.11.0",
|
||||||
|
note = "`app.configure_set(MySet.on_startup())` has been deprecated in favor of `app.configure_set(Startup, MySet)`. Please migrate to that API."
|
||||||
|
)]
|
||||||
|
fn on_startup(self) -> SystemSetConfigs {
|
||||||
|
panic!("`app.configure_set(MySet.on_startup())` has been deprecated in favor of `app.configure_set(Startup, MySet)`. Please migrate to that API.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This used to configure the set in the provided `schedule`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Always panics. Please migrate to the new `App::configure_set`:
|
||||||
|
/// Ex: `app.configure_set(MySet.in_schedule(SomeSchedule))` -> `app.configure_set(SomeSchedule, MySet)`
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.11.0",
|
||||||
|
note = "`app.configure_set(MySet.in_schedule(SomeSchedule))` has been deprecated in favor of `app.configure_set(SomeSchedule, MySet)`. Please migrate to that API."
|
||||||
|
)]
|
||||||
|
fn in_schedule(self, _schedule: impl ScheduleLabel) -> SystemSetConfigs {
|
||||||
|
panic!("`app.configure_set(MySet.in_schedule(SomeSchedule))` has been deprecated in favor of `app.configure_set(SomeSchedule, MySet)`. Please migrate to that API.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SystemSet> IntoSystemSetConfig for S {
|
impl<S: SystemSet> IntoSystemSetConfig for S {
|
||||||
|
@ -150,41 +488,10 @@ impl IntoSystemSetConfig for SystemSetConfig {
|
||||||
set.system_type().is_none(),
|
set.system_type().is_none(),
|
||||||
"adding arbitrary systems to a system type set is not allowed"
|
"adding arbitrary systems to a system type set is not allowed"
|
||||||
);
|
);
|
||||||
assert!(
|
|
||||||
!set.is_base(),
|
|
||||||
"Sets cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead."
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!self.set.is_base(),
|
|
||||||
"Base system sets cannot be added to other sets."
|
|
||||||
);
|
|
||||||
self.graph_info.sets.push(Box::new(set));
|
self.graph_info.sets.push(Box::new(set));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(mut self, set: impl SystemSet) -> Self {
|
|
||||||
assert!(
|
|
||||||
set.system_type().is_none(),
|
|
||||||
"System type sets cannot be base sets."
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
set.is_base(),
|
|
||||||
"Sets cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead."
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!self.set.is_base(),
|
|
||||||
"Base system sets cannot be added to other sets."
|
|
||||||
);
|
|
||||||
self.graph_info.set_base_set(Box::new(set));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn in_default_base_set(mut self) -> SystemSetConfig {
|
|
||||||
self.graph_info.add_default_base_set = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
||||||
self.graph_info.dependencies.push(Dependency::new(
|
self.graph_info.dependencies.push(Dependency::new(
|
||||||
DependencyKind::Before,
|
DependencyKind::Before,
|
||||||
|
@ -217,332 +524,6 @@ impl IntoSystemSetConfig for SystemSetConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Types that can be converted into a [`SystemConfig`].
|
|
||||||
///
|
|
||||||
/// This has been implemented for boxed [`System<In=(), Out=()>`](crate::system::System)
|
|
||||||
/// trait objects and all functions that turn into such.
|
|
||||||
pub trait IntoSystemConfig<Marker, Config = SystemConfig>: Sized
|
|
||||||
where
|
|
||||||
Config: IntoSystemConfig<(), Config>,
|
|
||||||
{
|
|
||||||
/// Convert into a [`SystemConfig`].
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn into_config(self) -> Config;
|
|
||||||
/// Add to `set` membership.
|
|
||||||
#[track_caller]
|
|
||||||
fn in_set(self, set: impl FreeSystemSet) -> Config {
|
|
||||||
self.into_config().in_set(set)
|
|
||||||
}
|
|
||||||
/// Add to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`].
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(self, set: impl BaseSystemSet) -> Config {
|
|
||||||
self.into_config().in_base_set(set)
|
|
||||||
}
|
|
||||||
/// Don't add this system to the schedules's default set.
|
|
||||||
fn no_default_base_set(self) -> Config {
|
|
||||||
self.into_config().no_default_base_set()
|
|
||||||
}
|
|
||||||
/// Run before all systems in `set`.
|
|
||||||
fn before<M>(self, set: impl IntoSystemSet<M>) -> Config {
|
|
||||||
self.into_config().before(set)
|
|
||||||
}
|
|
||||||
/// Run after all systems in `set`.
|
|
||||||
fn after<M>(self, set: impl IntoSystemSet<M>) -> Config {
|
|
||||||
self.into_config().after(set)
|
|
||||||
}
|
|
||||||
/// Run only if the [`Condition`] is `true`.
|
|
||||||
///
|
|
||||||
/// The `Condition` will be evaluated at most once (per schedule run),
|
|
||||||
/// when the system prepares to run.
|
|
||||||
fn run_if<M>(self, condition: impl Condition<M>) -> Config {
|
|
||||||
self.into_config().run_if(condition)
|
|
||||||
}
|
|
||||||
/// Suppress warnings and errors that would result from this system having ambiguities
|
|
||||||
/// (conflicting access but indeterminate order) with systems in `set`.
|
|
||||||
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> Config {
|
|
||||||
self.into_config().ambiguous_with(set)
|
|
||||||
}
|
|
||||||
/// Suppress warnings and errors that would result from this system having ambiguities
|
|
||||||
/// (conflicting access but indeterminate order) with any other system.
|
|
||||||
fn ambiguous_with_all(self) -> Config {
|
|
||||||
self.into_config().ambiguous_with_all()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Marker, F> IntoSystemConfig<Marker> for F
|
|
||||||
where
|
|
||||||
F: IntoSystem<(), (), Marker>,
|
|
||||||
{
|
|
||||||
fn into_config(self) -> SystemConfig {
|
|
||||||
SystemConfig::new(Box::new(IntoSystem::into_system(self)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystemConfig<()> for BoxedSystem<(), ()> {
|
|
||||||
fn into_config(self) -> SystemConfig {
|
|
||||||
SystemConfig::new(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystemConfig<()> for SystemConfig {
|
|
||||||
fn into_config(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_set(mut self, set: impl SystemSet) -> Self {
|
|
||||||
assert!(
|
|
||||||
set.system_type().is_none(),
|
|
||||||
"adding arbitrary systems to a system type set is not allowed"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!set.is_base(),
|
|
||||||
"Systems cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead."
|
|
||||||
);
|
|
||||||
self.graph_info.sets.push(Box::new(set));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(mut self, set: impl SystemSet) -> Self {
|
|
||||||
assert!(
|
|
||||||
set.system_type().is_none(),
|
|
||||||
"System type sets cannot be base sets."
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
set.is_base(),
|
|
||||||
"Systems cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead."
|
|
||||||
);
|
|
||||||
self.graph_info.set_base_set(Box::new(set));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn no_default_base_set(mut self) -> SystemConfig {
|
|
||||||
self.graph_info.add_default_base_set = false;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
self.graph_info.dependencies.push(Dependency::new(
|
|
||||||
DependencyKind::Before,
|
|
||||||
Box::new(set.into_system_set()),
|
|
||||||
));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
self.graph_info.dependencies.push(Dependency::new(
|
|
||||||
DependencyKind::After,
|
|
||||||
Box::new(set.into_system_set()),
|
|
||||||
));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_if<M>(mut self, condition: impl Condition<M>) -> Self {
|
|
||||||
self.conditions.push(new_condition(condition));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
ambiguous_with(&mut self.graph_info, Box::new(set.into_system_set()));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ambiguous_with_all(mut self) -> Self {
|
|
||||||
self.graph_info.ambiguous_with = Ambiguity::IgnoreAll;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A collection of [`SystemConfig`].
|
|
||||||
pub struct SystemConfigs {
|
|
||||||
pub(super) systems: Vec<SystemConfig>,
|
|
||||||
/// If `true`, adds `before -> after` ordering constraints between the successive elements.
|
|
||||||
pub(super) chained: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Types that can convert into a [`SystemConfigs`].
|
|
||||||
pub trait IntoSystemConfigs<Marker>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
/// Convert into a [`SystemConfigs`].
|
|
||||||
#[doc(hidden)]
|
|
||||||
fn into_configs(self) -> SystemConfigs;
|
|
||||||
|
|
||||||
/// Add these systems to the provided `set`.
|
|
||||||
#[track_caller]
|
|
||||||
fn in_set(self, set: impl FreeSystemSet) -> SystemConfigs {
|
|
||||||
self.into_configs().in_set(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add these systems to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`].
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(self, set: impl BaseSystemSet) -> SystemConfigs {
|
|
||||||
self.into_configs().in_base_set(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run before all systems in `set`.
|
|
||||||
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
|
|
||||||
self.into_configs().before(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run after all systems in `set`.
|
|
||||||
fn after<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
|
|
||||||
self.into_configs().after(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a run condition to each contained system.
|
|
||||||
///
|
|
||||||
/// The [`Condition`] must be [`Clone`]. Each system will receive its own clone
|
|
||||||
/// of the `Condition` and will only run if the `Condition` is true.
|
|
||||||
///
|
|
||||||
/// Each individual condition will be evaluated at most once (per schedule run),
|
|
||||||
/// right before the corresponding system prepares to run.
|
|
||||||
///
|
|
||||||
/// This is equivalent to calling [`run_if`](IntoSystemConfig::run_if) on each individual
|
|
||||||
/// system, as shown below:
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_ecs::prelude::*;
|
|
||||||
/// # let mut app = Schedule::new();
|
|
||||||
/// # fn a() {}
|
|
||||||
/// # fn b() {}
|
|
||||||
/// # fn condition() -> bool { true }
|
|
||||||
/// app.add_systems((a, b).distributive_run_if(condition));
|
|
||||||
/// app.add_systems((a.run_if(condition), b.run_if(condition)));
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Note
|
|
||||||
///
|
|
||||||
/// Because the conditions are evaluated separately for each system, there is no guarantee
|
|
||||||
/// that all evaluations in a single schedule run will yield the same result. If another
|
|
||||||
/// system is run inbetween two evaluations it could cause the result of the condition to change.
|
|
||||||
///
|
|
||||||
/// Use [`run_if`](IntoSystemSetConfig::run_if) on a [`SystemSet`] if you want to make sure
|
|
||||||
/// that either all or none of the systems are run, or you don't want to evaluate the run
|
|
||||||
/// condition for each contained system separately.
|
|
||||||
///
|
|
||||||
/// The [`Condition`] is cloned for each system.
|
|
||||||
/// Cloned instances of [`FunctionSystem`](crate::system::FunctionSystem) will be de-initialized.
|
|
||||||
fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> SystemConfigs {
|
|
||||||
self.into_configs().distributive_run_if(condition)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Suppress warnings and errors that would result from these systems having ambiguities
|
|
||||||
/// (conflicting access but indeterminate order) with systems in `set`.
|
|
||||||
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> SystemConfigs {
|
|
||||||
self.into_configs().ambiguous_with(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Suppress warnings and errors that would result from these systems having ambiguities
|
|
||||||
/// (conflicting access but indeterminate order) with any other system.
|
|
||||||
fn ambiguous_with_all(self) -> SystemConfigs {
|
|
||||||
self.into_configs().ambiguous_with_all()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Treat this collection as a sequence of systems.
|
|
||||||
///
|
|
||||||
/// Ordering constraints will be applied between the successive elements.
|
|
||||||
fn chain(self) -> SystemConfigs {
|
|
||||||
self.into_configs().chain()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoSystemConfigs<()> for SystemConfigs {
|
|
||||||
fn into_configs(self) -> Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_set(mut self, set: impl SystemSet) -> Self {
|
|
||||||
assert!(
|
|
||||||
set.system_type().is_none(),
|
|
||||||
"adding arbitrary systems to a system type set is not allowed"
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
!set.is_base(),
|
|
||||||
"Systems cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead."
|
|
||||||
);
|
|
||||||
for config in &mut self.systems {
|
|
||||||
config.graph_info.sets.push(set.dyn_clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(mut self, set: impl SystemSet) -> Self {
|
|
||||||
assert!(
|
|
||||||
set.system_type().is_none(),
|
|
||||||
"System type sets cannot be base sets."
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
set.is_base(),
|
|
||||||
"Systems cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead."
|
|
||||||
);
|
|
||||||
for config in &mut self.systems {
|
|
||||||
config.graph_info.set_base_set(set.dyn_clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
let set = set.into_system_set();
|
|
||||||
for config in &mut self.systems {
|
|
||||||
config
|
|
||||||
.graph_info
|
|
||||||
.dependencies
|
|
||||||
.push(Dependency::new(DependencyKind::Before, set.dyn_clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn after<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
let set = set.into_system_set();
|
|
||||||
for config in &mut self.systems {
|
|
||||||
config
|
|
||||||
.graph_info
|
|
||||||
.dependencies
|
|
||||||
.push(Dependency::new(DependencyKind::After, set.dyn_clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn distributive_run_if<M>(mut self, condition: impl Condition<M> + Clone) -> SystemConfigs {
|
|
||||||
for config in &mut self.systems {
|
|
||||||
config.conditions.push(new_condition(condition.clone()));
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ambiguous_with<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
|
||||||
let set = set.into_system_set();
|
|
||||||
for config in &mut self.systems {
|
|
||||||
ambiguous_with(&mut config.graph_info, set.dyn_clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ambiguous_with_all(mut self) -> Self {
|
|
||||||
for config in &mut self.systems {
|
|
||||||
config.graph_info.ambiguous_with = Ambiguity::IgnoreAll;
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn chain(mut self) -> Self {
|
|
||||||
self.chained = true;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A collection of [`SystemSetConfig`].
|
/// A collection of [`SystemSetConfig`].
|
||||||
pub struct SystemSetConfigs {
|
pub struct SystemSetConfigs {
|
||||||
pub(super) sets: Vec<SystemSetConfig>,
|
pub(super) sets: Vec<SystemSetConfig>,
|
||||||
|
@ -561,16 +542,10 @@ where
|
||||||
|
|
||||||
/// Add these system sets to the provided `set`.
|
/// Add these system sets to the provided `set`.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfigs {
|
fn in_set(self, set: impl SystemSet) -> SystemSetConfigs {
|
||||||
self.into_configs().in_set(set)
|
self.into_configs().in_set(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add these system sets to the provided "base" `set`. For more information on base sets, see [`SystemSet::is_base`].
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(self, set: impl BaseSystemSet) -> SystemSetConfigs {
|
|
||||||
self.into_configs().in_base_set(set)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run before all systems in `set`.
|
/// Run before all systems in `set`.
|
||||||
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
|
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
|
||||||
self.into_configs().before(set)
|
self.into_configs().before(set)
|
||||||
|
@ -599,6 +574,35 @@ where
|
||||||
fn chain(self) -> SystemSetConfigs {
|
fn chain(self) -> SystemSetConfigs {
|
||||||
self.into_configs().chain()
|
self.into_configs().chain()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This used to configure the sets in the `CoreSchedule::Startup` schedule.
|
||||||
|
/// This was a shorthand for `self.in_schedule(CoreSchedule::Startup)`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Always panics. Please migrate to the new `App::configure_sets` with the `Startup` schedule:
|
||||||
|
/// Ex: `app.configure_sets((A, B).on_startup())` -> `app.configure_sets(Startup, (A, B))`
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.11.0",
|
||||||
|
note = "`app.configure_sets((A, B).on_startup())` has been deprecated in favor of `app.configure_sets(Startup, (A, B))`. Please migrate to that API."
|
||||||
|
)]
|
||||||
|
fn on_startup(self) -> SystemSetConfigs {
|
||||||
|
panic!("`app.configure_sets((A, B).on_startup())` has been deprecated in favor of `app.configure_sets(Startup, (A, B))`. Please migrate to that API.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This used to configure the sets in the provided `schedule`.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Always panics. Please migrate to the new `App::configure_set`:
|
||||||
|
/// Ex: `app.configure_sets((A, B).in_schedule(SomeSchedule))` -> `app.configure_sets(SomeSchedule, (A, B))`
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.11.0",
|
||||||
|
note = "`app.configure_sets((A, B).in_schedule(SomeSchedule))` has been deprecated in favor of `app.configure_sets(SomeSchedule, (A, B))`. Please migrate to that API."
|
||||||
|
)]
|
||||||
|
fn in_schedule(self, _schedule: impl ScheduleLabel) -> SystemSetConfigs {
|
||||||
|
panic!("`app.configure_sets((A, B).in_schedule(SomeSchedule))` has been deprecated in favor of `app.configure_sets(SomeSchedule, (A, B))`. Please migrate to that API.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoSystemSetConfigs for SystemSetConfigs {
|
impl IntoSystemSetConfigs for SystemSetConfigs {
|
||||||
|
@ -612,42 +616,13 @@ impl IntoSystemSetConfigs for SystemSetConfigs {
|
||||||
set.system_type().is_none(),
|
set.system_type().is_none(),
|
||||||
"adding arbitrary systems to a system type set is not allowed"
|
"adding arbitrary systems to a system type set is not allowed"
|
||||||
);
|
);
|
||||||
assert!(
|
|
||||||
!set.is_base(),
|
|
||||||
"Sets cannot be added to 'base' system sets using 'in_set'. Use 'in_base_set' instead."
|
|
||||||
);
|
|
||||||
for config in &mut self.sets {
|
for config in &mut self.sets {
|
||||||
assert!(
|
|
||||||
!config.set.is_base(),
|
|
||||||
"Base system sets cannot be added to other sets."
|
|
||||||
);
|
|
||||||
config.graph_info.sets.push(set.dyn_clone());
|
config.graph_info.sets.push(set.dyn_clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
fn in_base_set(mut self, set: impl SystemSet) -> Self {
|
|
||||||
assert!(
|
|
||||||
set.system_type().is_none(),
|
|
||||||
"System type sets cannot be base sets."
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
set.is_base(),
|
|
||||||
"Sets cannot be added to normal sets using 'in_base_set'. Use 'in_set' instead."
|
|
||||||
);
|
|
||||||
for config in &mut self.sets {
|
|
||||||
assert!(
|
|
||||||
!config.set.is_base(),
|
|
||||||
"Base system sets cannot be added to other sets."
|
|
||||||
);
|
|
||||||
config.graph_info.set_base_set(set.dyn_clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
fn before<M>(mut self, set: impl IntoSystemSet<M>) -> Self {
|
||||||
let set = set.into_system_set();
|
let set = set.into_system_set();
|
||||||
for config in &mut self.sets {
|
for config in &mut self.sets {
|
||||||
|
@ -695,24 +670,6 @@ impl IntoSystemSetConfigs for SystemSetConfigs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_system_collection {
|
|
||||||
($(($param: ident, $sys: ident)),*) => {
|
|
||||||
impl<$($param, $sys),*> IntoSystemConfigs<($($param,)*)> for ($($sys,)*)
|
|
||||||
where
|
|
||||||
$($sys: IntoSystemConfig<$param>),*
|
|
||||||
{
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn into_configs(self) -> SystemConfigs {
|
|
||||||
let ($($sys,)*) = self;
|
|
||||||
SystemConfigs {
|
|
||||||
systems: vec![$($sys.into_config(),)*],
|
|
||||||
chained: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_system_set_collection {
|
macro_rules! impl_system_set_collection {
|
||||||
($($set: ident),*) => {
|
($($set: ident),*) => {
|
||||||
impl<$($set: IntoSystemSetConfig),*> IntoSystemSetConfigs for ($($set,)*)
|
impl<$($set: IntoSystemSetConfig),*> IntoSystemSetConfigs for ($($set,)*)
|
||||||
|
@ -729,5 +686,4 @@ macro_rules! impl_system_set_collection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
all_tuples!(impl_system_collection, 0, 15, P, S);
|
|
||||||
all_tuples!(impl_system_set_collection, 0, 15, S);
|
all_tuples!(impl_system_set_collection, 0, 15, S);
|
||||||
|
|
|
@ -67,56 +67,14 @@ pub(crate) enum Ambiguity {
|
||||||
IgnoreAll,
|
IgnoreAll,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Default)]
|
||||||
pub(crate) struct GraphInfo {
|
pub(crate) struct GraphInfo {
|
||||||
pub(crate) sets: Vec<BoxedSystemSet>,
|
pub(crate) sets: Vec<BoxedSystemSet>,
|
||||||
pub(crate) dependencies: Vec<Dependency>,
|
pub(crate) dependencies: Vec<Dependency>,
|
||||||
pub(crate) ambiguous_with: Ambiguity,
|
pub(crate) ambiguous_with: Ambiguity,
|
||||||
pub(crate) add_default_base_set: bool,
|
|
||||||
pub(crate) base_set: Option<BoxedSystemSet>,
|
pub(crate) base_set: Option<BoxedSystemSet>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GraphInfo {
|
|
||||||
fn default() -> Self {
|
|
||||||
GraphInfo {
|
|
||||||
sets: Vec::new(),
|
|
||||||
base_set: None,
|
|
||||||
dependencies: Vec::new(),
|
|
||||||
ambiguous_with: Ambiguity::default(),
|
|
||||||
add_default_base_set: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GraphInfo {
|
|
||||||
pub(crate) fn system() -> GraphInfo {
|
|
||||||
GraphInfo {
|
|
||||||
// systems get the default base set automatically
|
|
||||||
add_default_base_set: true,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn system_set() -> GraphInfo {
|
|
||||||
GraphInfo {
|
|
||||||
// sets do not get the default base set automatically
|
|
||||||
add_default_base_set: false,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[track_caller]
|
|
||||||
pub(crate) fn set_base_set(&mut self, set: BoxedSystemSet) {
|
|
||||||
if let Some(current) = &self.base_set {
|
|
||||||
panic!(
|
|
||||||
"Cannot set the base set because base set {current:?} has already been configured."
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
self.base_set = Some(set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts 2D row-major pair of indices into a 1D array index.
|
/// Converts 2D row-major pair of indices into a 1D array index.
|
||||||
pub(crate) fn index(row: usize, col: usize, num_cols: usize) -> usize {
|
pub(crate) fn index(row: usize, col: usize, num_cols: usize) -> usize {
|
||||||
debug_assert!(col < num_cols);
|
debug_assert!(col < num_cols);
|
||||||
|
|
|
@ -23,7 +23,7 @@ mod tests {
|
||||||
use std::sync::atomic::{AtomicU32, Ordering};
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
|
||||||
pub use crate as bevy_ecs;
|
pub use crate as bevy_ecs;
|
||||||
pub use crate::schedule::{IntoSystemConfig, IntoSystemSetConfig, Schedule, SystemSet};
|
pub use crate::schedule::{IntoSystemSetConfig, Schedule, SystemSet};
|
||||||
pub use crate::system::{Res, ResMut};
|
pub use crate::system::{Res, ResMut};
|
||||||
pub use crate::{prelude::World, system::Resource};
|
pub use crate::{prelude::World, system::Resource};
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ mod tests {
|
||||||
|
|
||||||
world.init_resource::<SystemOrder>();
|
world.init_resource::<SystemOrder>();
|
||||||
|
|
||||||
schedule.add_system(make_function_system(0));
|
schedule.add_systems(make_function_system(0));
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
||||||
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
|
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
|
||||||
|
@ -88,7 +88,7 @@ mod tests {
|
||||||
|
|
||||||
world.init_resource::<SystemOrder>();
|
world.init_resource::<SystemOrder>();
|
||||||
|
|
||||||
schedule.add_system(make_exclusive_system(0));
|
schedule.add_systems(make_exclusive_system(0));
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
||||||
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
|
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
|
||||||
|
@ -108,7 +108,7 @@ mod tests {
|
||||||
|
|
||||||
for _ in 0..thread_count {
|
for _ in 0..thread_count {
|
||||||
let inner = barrier.clone();
|
let inner = barrier.clone();
|
||||||
schedule.add_system(move || {
|
schedule.add_systems(move || {
|
||||||
inner.wait();
|
inner.wait();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -195,6 +195,50 @@ mod tests {
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
assert_eq!(world.resource::<SystemOrder>().0, vec![0, 1, 2, 3]);
|
assert_eq!(world.resource::<SystemOrder>().0, vec![0, 1, 2, 3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_systems_correct_order_nested() {
|
||||||
|
let mut world = World::new();
|
||||||
|
let mut schedule = Schedule::new();
|
||||||
|
|
||||||
|
world.init_resource::<SystemOrder>();
|
||||||
|
|
||||||
|
schedule.add_systems(
|
||||||
|
(
|
||||||
|
(make_function_system(0), make_function_system(1)).chain(),
|
||||||
|
make_function_system(2),
|
||||||
|
(make_function_system(3), make_function_system(4)).chain(),
|
||||||
|
(
|
||||||
|
make_function_system(5),
|
||||||
|
(make_function_system(6), make_function_system(7)),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
(make_function_system(8), make_function_system(9)).chain(),
|
||||||
|
make_function_system(10),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.chain(),
|
||||||
|
);
|
||||||
|
|
||||||
|
schedule.run(&mut world);
|
||||||
|
let order = &world.resource::<SystemOrder>().0;
|
||||||
|
assert_eq!(
|
||||||
|
&order[0..5],
|
||||||
|
&[0, 1, 2, 3, 4],
|
||||||
|
"first five items should be exactly ordered"
|
||||||
|
);
|
||||||
|
let unordered = &order[5..8];
|
||||||
|
assert!(
|
||||||
|
unordered.contains(&5) && unordered.contains(&6) && unordered.contains(&7),
|
||||||
|
"unordered must be 5, 6, and 7 in any order"
|
||||||
|
);
|
||||||
|
let partially_ordered = &order[8..11];
|
||||||
|
assert!(
|
||||||
|
partially_ordered == [8, 9, 10] || partially_ordered == [10, 8, 9],
|
||||||
|
"partially_ordered must be [8, 9, 10] or [10, 8, 9]"
|
||||||
|
);
|
||||||
|
assert!(order.len() == 11, "must have exacty 11 order entries");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod conditions {
|
mod conditions {
|
||||||
|
@ -210,7 +254,7 @@ mod tests {
|
||||||
world.init_resource::<RunConditionBool>();
|
world.init_resource::<RunConditionBool>();
|
||||||
world.init_resource::<SystemOrder>();
|
world.init_resource::<SystemOrder>();
|
||||||
|
|
||||||
schedule.add_system(
|
schedule.add_systems(
|
||||||
make_function_system(0).run_if(|condition: Res<RunConditionBool>| condition.0),
|
make_function_system(0).run_if(|condition: Res<RunConditionBool>| condition.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -256,7 +300,7 @@ mod tests {
|
||||||
world.init_resource::<RunConditionBool>();
|
world.init_resource::<RunConditionBool>();
|
||||||
world.init_resource::<SystemOrder>();
|
world.init_resource::<SystemOrder>();
|
||||||
|
|
||||||
schedule.add_system(
|
schedule.add_systems(
|
||||||
make_exclusive_system(0).run_if(|condition: Res<RunConditionBool>| condition.0),
|
make_exclusive_system(0).run_if(|condition: Res<RunConditionBool>| condition.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -294,13 +338,13 @@ mod tests {
|
||||||
world.init_resource::<Counter>();
|
world.init_resource::<Counter>();
|
||||||
|
|
||||||
schedule.configure_set(TestSet::A.run_if(|| false).run_if(|| false));
|
schedule.configure_set(TestSet::A.run_if(|| false).run_if(|| false));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::A));
|
schedule.add_systems(counting_system.in_set(TestSet::A));
|
||||||
schedule.configure_set(TestSet::B.run_if(|| true).run_if(|| false));
|
schedule.configure_set(TestSet::B.run_if(|| true).run_if(|| false));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::B));
|
schedule.add_systems(counting_system.in_set(TestSet::B));
|
||||||
schedule.configure_set(TestSet::C.run_if(|| false).run_if(|| true));
|
schedule.configure_set(TestSet::C.run_if(|| false).run_if(|| true));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::C));
|
schedule.add_systems(counting_system.in_set(TestSet::C));
|
||||||
schedule.configure_set(TestSet::D.run_if(|| true).run_if(|| true));
|
schedule.configure_set(TestSet::D.run_if(|| true).run_if(|| true));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::D));
|
schedule.add_systems(counting_system.in_set(TestSet::D));
|
||||||
|
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
assert_eq!(world.resource::<Counter>().0.load(Ordering::Relaxed), 1);
|
assert_eq!(world.resource::<Counter>().0.load(Ordering::Relaxed), 1);
|
||||||
|
@ -314,13 +358,13 @@ mod tests {
|
||||||
world.init_resource::<Counter>();
|
world.init_resource::<Counter>();
|
||||||
|
|
||||||
schedule.configure_set(TestSet::A.run_if(|| false));
|
schedule.configure_set(TestSet::A.run_if(|| false));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::A).run_if(|| false));
|
schedule.add_systems(counting_system.in_set(TestSet::A).run_if(|| false));
|
||||||
schedule.configure_set(TestSet::B.run_if(|| true));
|
schedule.configure_set(TestSet::B.run_if(|| true));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::B).run_if(|| false));
|
schedule.add_systems(counting_system.in_set(TestSet::B).run_if(|| false));
|
||||||
schedule.configure_set(TestSet::C.run_if(|| false));
|
schedule.configure_set(TestSet::C.run_if(|| false));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::C).run_if(|| true));
|
schedule.add_systems(counting_system.in_set(TestSet::C).run_if(|| true));
|
||||||
schedule.configure_set(TestSet::D.run_if(|| true));
|
schedule.configure_set(TestSet::D.run_if(|| true));
|
||||||
schedule.add_system(counting_system.in_set(TestSet::D).run_if(|| true));
|
schedule.add_systems(counting_system.in_set(TestSet::D).run_if(|| true));
|
||||||
|
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
assert_eq!(world.resource::<Counter>().0.load(Ordering::Relaxed), 1);
|
assert_eq!(world.resource::<Counter>().0.load(Ordering::Relaxed), 1);
|
||||||
|
@ -337,7 +381,7 @@ mod tests {
|
||||||
world.init_resource::<Bool2>();
|
world.init_resource::<Bool2>();
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
|
|
||||||
schedule.add_system(
|
schedule.add_systems(
|
||||||
counting_system
|
counting_system
|
||||||
.run_if(|res1: Res<RunConditionBool>| res1.is_changed())
|
.run_if(|res1: Res<RunConditionBool>| res1.is_changed())
|
||||||
.run_if(|res2: Res<Bool2>| res2.is_changed()),
|
.run_if(|res2: Res<Bool2>| res2.is_changed()),
|
||||||
|
@ -391,7 +435,7 @@ mod tests {
|
||||||
.run_if(|res2: Res<Bool2>| res2.is_changed()),
|
.run_if(|res2: Res<Bool2>| res2.is_changed()),
|
||||||
);
|
);
|
||||||
|
|
||||||
schedule.add_system(counting_system.in_set(TestSet::A));
|
schedule.add_systems(counting_system.in_set(TestSet::A));
|
||||||
|
|
||||||
// both resource were just added.
|
// both resource were just added.
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
@ -438,7 +482,7 @@ mod tests {
|
||||||
schedule
|
schedule
|
||||||
.configure_set(TestSet::A.run_if(|res1: Res<RunConditionBool>| res1.is_changed()));
|
.configure_set(TestSet::A.run_if(|res1: Res<RunConditionBool>| res1.is_changed()));
|
||||||
|
|
||||||
schedule.add_system(
|
schedule.add_systems(
|
||||||
counting_system
|
counting_system
|
||||||
.run_if(|res2: Res<Bool2>| res2.is_changed())
|
.run_if(|res2: Res<Bool2>| res2.is_changed())
|
||||||
.in_set(TestSet::A),
|
.in_set(TestSet::A),
|
||||||
|
@ -544,7 +588,7 @@ mod tests {
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
// Schedule another `foo`.
|
// Schedule another `foo`.
|
||||||
schedule.add_system(foo);
|
schedule.add_systems(foo);
|
||||||
|
|
||||||
// When there are multiple instances of `foo`, dependencies on
|
// When there are multiple instances of `foo`, dependencies on
|
||||||
// `foo` are no longer allowed. Too much ambiguity.
|
// `foo` are no longer allowed. Too much ambiguity.
|
||||||
|
@ -556,11 +600,11 @@ mod tests {
|
||||||
|
|
||||||
// same goes for `ambiguous_with`
|
// same goes for `ambiguous_with`
|
||||||
let mut schedule = Schedule::new();
|
let mut schedule = Schedule::new();
|
||||||
schedule.add_system(foo);
|
schedule.add_systems(foo);
|
||||||
schedule.add_system(bar.ambiguous_with(foo));
|
schedule.add_systems(bar.ambiguous_with(foo));
|
||||||
let result = schedule.initialize(&mut world);
|
let result = schedule.initialize(&mut world);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
schedule.add_system(foo);
|
schedule.add_systems(foo);
|
||||||
let result = schedule.initialize(&mut world);
|
let result = schedule.initialize(&mut world);
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
|
@ -626,7 +670,7 @@ mod tests {
|
||||||
fn foo() {}
|
fn foo() {}
|
||||||
|
|
||||||
// Add `foo` to both `A` and `C`.
|
// Add `foo` to both `A` and `C`.
|
||||||
schedule.add_system(foo.in_set(TestSet::A).in_set(TestSet::C));
|
schedule.add_systems(foo.in_set(TestSet::A).in_set(TestSet::C));
|
||||||
|
|
||||||
// Order `A -> B -> C`.
|
// Order `A -> B -> C`.
|
||||||
schedule.configure_sets((
|
schedule.configure_sets((
|
||||||
|
@ -664,140 +708,4 @@ mod tests {
|
||||||
assert!(matches!(result, Err(ScheduleBuildError::Ambiguity)));
|
assert!(matches!(result, Err(ScheduleBuildError::Ambiguity)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod base_sets {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(SystemSet, Hash, Debug, Eq, PartialEq, Clone)]
|
|
||||||
#[system_set(base)]
|
|
||||||
enum Base {
|
|
||||||
A,
|
|
||||||
B,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(SystemSet, Hash, Debug, Eq, PartialEq, Clone)]
|
|
||||||
enum Normal {
|
|
||||||
X,
|
|
||||||
Y,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn disallow_adding_base_sets_to_sets() {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.configure_set(Base::A.in_set(Normal::X));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn disallow_adding_base_sets_to_base_sets() {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.configure_set(Base::A.in_base_set(Base::B));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn disallow_adding_set_to_multiple_base_sets() {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.configure_set(Normal::X.in_base_set(Base::A).in_base_set(Base::B));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn disallow_adding_sets_to_multiple_base_sets() {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.configure_sets(
|
|
||||||
(Normal::X, Normal::Y)
|
|
||||||
.in_base_set(Base::A)
|
|
||||||
.in_base_set(Base::B),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn disallow_adding_system_to_multiple_base_sets() {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.add_system(named_system.in_base_set(Base::A).in_base_set(Base::B));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[should_panic]
|
|
||||||
fn disallow_adding_systems_to_multiple_base_sets() {
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule.add_systems(
|
|
||||||
(make_function_system(0), make_function_system(1))
|
|
||||||
.in_base_set(Base::A)
|
|
||||||
.in_base_set(Base::B),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn disallow_multiple_base_sets() {
|
|
||||||
let mut world = World::new();
|
|
||||||
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule
|
|
||||||
.configure_set(Normal::X.in_base_set(Base::A))
|
|
||||||
.configure_set(Normal::Y.in_base_set(Base::B))
|
|
||||||
.add_system(named_system.in_set(Normal::X).in_set(Normal::Y));
|
|
||||||
|
|
||||||
let result = schedule.initialize(&mut world);
|
|
||||||
assert!(matches!(
|
|
||||||
result,
|
|
||||||
Err(ScheduleBuildError::SystemInMultipleBaseSets { .. })
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule
|
|
||||||
.configure_set(Normal::X.in_base_set(Base::A))
|
|
||||||
.configure_set(Normal::Y.in_base_set(Base::B).in_set(Normal::X));
|
|
||||||
|
|
||||||
let result = schedule.initialize(&mut world);
|
|
||||||
assert!(matches!(
|
|
||||||
result,
|
|
||||||
Err(ScheduleBuildError::SetInMultipleBaseSets { .. })
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn allow_same_base_sets() {
|
|
||||||
let mut world = World::new();
|
|
||||||
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule
|
|
||||||
.configure_set(Normal::X.in_base_set(Base::A))
|
|
||||||
.configure_set(Normal::Y.in_base_set(Base::A))
|
|
||||||
.add_system(named_system.in_set(Normal::X).in_set(Normal::Y));
|
|
||||||
|
|
||||||
let result = schedule.initialize(&mut world);
|
|
||||||
assert!(matches!(result, Ok(())));
|
|
||||||
|
|
||||||
let mut schedule = Schedule::new();
|
|
||||||
schedule
|
|
||||||
.configure_set(Normal::X.in_base_set(Base::A))
|
|
||||||
.configure_set(Normal::Y.in_base_set(Base::A).in_set(Normal::X));
|
|
||||||
|
|
||||||
let result = schedule.initialize(&mut world);
|
|
||||||
assert!(matches!(result, Ok(())));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn default_base_set_ordering() {
|
|
||||||
let mut world = World::default();
|
|
||||||
let mut schedule = Schedule::default();
|
|
||||||
|
|
||||||
world.init_resource::<SystemOrder>();
|
|
||||||
|
|
||||||
schedule
|
|
||||||
.set_default_base_set(Base::A)
|
|
||||||
.configure_set(Base::A.before(Base::B))
|
|
||||||
.add_systems((
|
|
||||||
make_function_system(0).in_base_set(Base::B),
|
|
||||||
make_function_system(1),
|
|
||||||
));
|
|
||||||
schedule.run(&mut world);
|
|
||||||
|
|
||||||
assert_eq!(world.resource::<SystemOrder>().0, vec![1, 0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,17 +43,11 @@ impl Schedules {
|
||||||
/// and the old schedule is returned. Otherwise, `None` is returned.
|
/// and the old schedule is returned. Otherwise, `None` is returned.
|
||||||
pub fn insert(&mut self, label: impl ScheduleLabel, schedule: Schedule) -> Option<Schedule> {
|
pub fn insert(&mut self, label: impl ScheduleLabel, schedule: Schedule) -> Option<Schedule> {
|
||||||
let label = label.dyn_clone();
|
let label = label.dyn_clone();
|
||||||
if self.inner.contains_key(&label) {
|
|
||||||
warn!("schedule with label {:?} already exists", label);
|
|
||||||
}
|
|
||||||
self.inner.insert(label, schedule)
|
self.inner.insert(label, schedule)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the schedule corresponding to the `label` from the map, returning it if it existed.
|
/// Removes the schedule corresponding to the `label` from the map, returning it if it existed.
|
||||||
pub fn remove(&mut self, label: &dyn ScheduleLabel) -> Option<Schedule> {
|
pub fn remove(&mut self, label: &dyn ScheduleLabel) -> Option<Schedule> {
|
||||||
if !self.inner.contains_key(label) {
|
|
||||||
warn!("schedule with label {:?} not found", label);
|
|
||||||
}
|
|
||||||
self.inner.remove(label)
|
self.inner.remove(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +56,6 @@ impl Schedules {
|
||||||
&mut self,
|
&mut self,
|
||||||
label: &dyn ScheduleLabel,
|
label: &dyn ScheduleLabel,
|
||||||
) -> Option<(Box<dyn ScheduleLabel>, Schedule)> {
|
) -> Option<(Box<dyn ScheduleLabel>, Schedule)> {
|
||||||
if !self.inner.contains_key(label) {
|
|
||||||
warn!("schedule with label {:?} not found", label);
|
|
||||||
}
|
|
||||||
self.inner.remove_entry(label)
|
self.inner.remove_entry(label)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +125,7 @@ fn make_executor(kind: ExecutorKind) -> Box<dyn SystemExecutor> {
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let mut world = World::new();
|
/// let mut world = World::new();
|
||||||
/// let mut schedule = Schedule::default();
|
/// let mut schedule = Schedule::default();
|
||||||
/// schedule.add_system(hello_world);
|
/// schedule.add_systems(hello_world);
|
||||||
///
|
///
|
||||||
/// schedule.run(&mut world);
|
/// schedule.run(&mut world);
|
||||||
/// }
|
/// }
|
||||||
|
@ -183,21 +174,16 @@ impl Schedule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_default_base_set(&mut self, default_base_set: impl SystemSet) -> &mut Self {
|
|
||||||
self.graph
|
|
||||||
.set_default_base_set(Some(Box::new(default_base_set)));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a system to the schedule.
|
/// Add a system to the schedule.
|
||||||
pub fn add_system<M>(&mut self, system: impl IntoSystemConfig<M>) -> &mut Self {
|
#[deprecated(since = "0.11.0", note = "please use `add_systems` instead")]
|
||||||
self.graph.add_system(system);
|
pub fn add_system<M>(&mut self, system: impl IntoSystemConfigs<M>) -> &mut Self {
|
||||||
|
self.graph.add_systems_inner(system.into_configs(), false);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a collection of systems to the schedule.
|
/// Add a collection of systems to the schedule.
|
||||||
pub fn add_systems<M>(&mut self, systems: impl IntoSystemConfigs<M>) -> &mut Self {
|
pub fn add_systems<M>(&mut self, systems: impl IntoSystemConfigs<M>) -> &mut Self {
|
||||||
self.graph.add_systems(systems);
|
self.graph.add_systems_inner(systems.into_configs(), false);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,29 +332,14 @@ impl Dag {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes which base set (i.e. [`SystemSet`] where [`SystemSet::is_base`] returns true)
|
|
||||||
/// a system belongs to.
|
|
||||||
///
|
|
||||||
/// Note that this is only populated once [`ScheduleGraph::build_schedule`] is called.
|
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
|
||||||
pub enum BaseSetMembership {
|
|
||||||
Uncalculated,
|
|
||||||
None,
|
|
||||||
Some(NodeId),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`SystemSet`] with metadata, stored in a [`ScheduleGraph`].
|
/// A [`SystemSet`] with metadata, stored in a [`ScheduleGraph`].
|
||||||
struct SystemSetNode {
|
struct SystemSetNode {
|
||||||
inner: BoxedSystemSet,
|
inner: BoxedSystemSet,
|
||||||
base_set_membership: BaseSetMembership,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemSetNode {
|
impl SystemSetNode {
|
||||||
pub fn new(set: BoxedSystemSet) -> Self {
|
pub fn new(set: BoxedSystemSet) -> Self {
|
||||||
Self {
|
Self { inner: set }
|
||||||
inner: set,
|
|
||||||
base_set_membership: BaseSetMembership::Uncalculated,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> String {
|
pub fn name(&self) -> String {
|
||||||
|
@ -383,14 +354,12 @@ impl SystemSetNode {
|
||||||
/// A [`BoxedSystem`] with metadata, stored in a [`ScheduleGraph`].
|
/// A [`BoxedSystem`] with metadata, stored in a [`ScheduleGraph`].
|
||||||
struct SystemNode {
|
struct SystemNode {
|
||||||
inner: Option<BoxedSystem>,
|
inner: Option<BoxedSystem>,
|
||||||
base_set_membership: BaseSetMembership,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemNode {
|
impl SystemNode {
|
||||||
pub fn new(system: BoxedSystem) -> Self {
|
pub fn new(system: BoxedSystem) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Some(system),
|
inner: Some(system),
|
||||||
base_set_membership: BaseSetMembership::Uncalculated,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,10 +370,6 @@ impl SystemNode {
|
||||||
pub fn get_mut(&mut self) -> Option<&mut BoxedSystem> {
|
pub fn get_mut(&mut self) -> Option<&mut BoxedSystem> {
|
||||||
self.inner.as_mut()
|
self.inner.as_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> String {
|
|
||||||
format!("{:?}", &self.inner)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Metadata for a [`Schedule`].
|
/// Metadata for a [`Schedule`].
|
||||||
|
@ -416,7 +381,6 @@ pub struct ScheduleGraph {
|
||||||
system_set_conditions: Vec<Option<Vec<BoxedCondition>>>,
|
system_set_conditions: Vec<Option<Vec<BoxedCondition>>>,
|
||||||
system_set_ids: HashMap<BoxedSystemSet, NodeId>,
|
system_set_ids: HashMap<BoxedSystemSet, NodeId>,
|
||||||
uninit: Vec<(NodeId, usize)>,
|
uninit: Vec<(NodeId, usize)>,
|
||||||
maybe_default_base_set: Vec<NodeId>,
|
|
||||||
hierarchy: Dag,
|
hierarchy: Dag,
|
||||||
dependency: Dag,
|
dependency: Dag,
|
||||||
dependency_flattened: Dag,
|
dependency_flattened: Dag,
|
||||||
|
@ -426,7 +390,6 @@ pub struct ScheduleGraph {
|
||||||
conflicting_systems: Vec<(NodeId, NodeId, Vec<ComponentId>)>,
|
conflicting_systems: Vec<(NodeId, NodeId, Vec<ComponentId>)>,
|
||||||
changed: bool,
|
changed: bool,
|
||||||
settings: ScheduleBuildSettings,
|
settings: ScheduleBuildSettings,
|
||||||
default_base_set: Option<BoxedSystemSet>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScheduleGraph {
|
impl ScheduleGraph {
|
||||||
|
@ -437,7 +400,6 @@ impl ScheduleGraph {
|
||||||
system_sets: Vec::new(),
|
system_sets: Vec::new(),
|
||||||
system_set_conditions: Vec::new(),
|
system_set_conditions: Vec::new(),
|
||||||
system_set_ids: HashMap::new(),
|
system_set_ids: HashMap::new(),
|
||||||
maybe_default_base_set: Vec::new(),
|
|
||||||
uninit: Vec::new(),
|
uninit: Vec::new(),
|
||||||
hierarchy: Dag::new(),
|
hierarchy: Dag::new(),
|
||||||
dependency: Dag::new(),
|
dependency: Dag::new(),
|
||||||
|
@ -448,7 +410,6 @@ impl ScheduleGraph {
|
||||||
conflicting_systems: Vec::new(),
|
conflicting_systems: Vec::new(),
|
||||||
changed: false,
|
changed: false,
|
||||||
settings: default(),
|
settings: default(),
|
||||||
default_base_set: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,44 +452,29 @@ impl ScheduleGraph {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all systems in this schedule.
|
/// Returns an iterator over all systems in this schedule.
|
||||||
///
|
|
||||||
/// Note that the [`BaseSetMembership`] will only be initialized after [`ScheduleGraph::build_schedule`] is called.
|
|
||||||
pub fn systems(
|
pub fn systems(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<
|
) -> impl Iterator<Item = (NodeId, &dyn System<In = (), Out = ()>, &[BoxedCondition])> {
|
||||||
Item = (
|
|
||||||
NodeId,
|
|
||||||
&dyn System<In = (), Out = ()>,
|
|
||||||
BaseSetMembership,
|
|
||||||
&[BoxedCondition],
|
|
||||||
),
|
|
||||||
> {
|
|
||||||
self.systems
|
self.systems
|
||||||
.iter()
|
.iter()
|
||||||
.zip(self.system_conditions.iter())
|
.zip(self.system_conditions.iter())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.filter_map(|(i, (system_node, condition))| {
|
.filter_map(|(i, (system_node, condition))| {
|
||||||
let system = system_node.inner.as_deref()?;
|
let system = system_node.inner.as_deref()?;
|
||||||
let base_set_membership = system_node.base_set_membership;
|
|
||||||
let condition = condition.as_ref()?.as_slice();
|
let condition = condition.as_ref()?.as_slice();
|
||||||
Some((NodeId::System(i), system, base_set_membership, condition))
|
Some((NodeId::System(i), system, condition))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an iterator over all system sets in this schedule.
|
/// Returns an iterator over all system sets in this schedule.
|
||||||
///
|
pub fn system_sets(&self) -> impl Iterator<Item = (NodeId, &dyn SystemSet, &[BoxedCondition])> {
|
||||||
/// Note that the [`BaseSetMembership`] will only be initialized after [`ScheduleGraph::build_schedule`] is called.
|
|
||||||
pub fn system_sets(
|
|
||||||
&self,
|
|
||||||
) -> impl Iterator<Item = (NodeId, &dyn SystemSet, BaseSetMembership, &[BoxedCondition])> {
|
|
||||||
self.system_set_ids.iter().map(|(_, node_id)| {
|
self.system_set_ids.iter().map(|(_, node_id)| {
|
||||||
let set_node = &self.system_sets[node_id.index()];
|
let set_node = &self.system_sets[node_id.index()];
|
||||||
let set = &*set_node.inner;
|
let set = &*set_node.inner;
|
||||||
let base_set_membership = set_node.base_set_membership;
|
|
||||||
let conditions = self.system_set_conditions[node_id.index()]
|
let conditions = self.system_set_conditions[node_id.index()]
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or(&[]);
|
.unwrap_or(&[]);
|
||||||
(*node_id, set, base_set_membership, conditions)
|
(*node_id, set, conditions)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,47 +502,144 @@ impl ScheduleGraph {
|
||||||
&self.conflicting_systems
|
&self.conflicting_systems
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_systems<M>(&mut self, systems: impl IntoSystemConfigs<M>) {
|
/// Adds the systems to the graph. Returns a vector of all node ids contained the nested `SystemConfigs`
|
||||||
let SystemConfigs { systems, chained } = systems.into_configs();
|
/// if `ancestor_chained` is true. Also returns true if "densely chained", meaning that all nested items
|
||||||
let mut system_iter = systems.into_iter();
|
/// are linearly chained in the order they are defined
|
||||||
if chained {
|
fn add_systems_inner(
|
||||||
let Some(prev) = system_iter.next() else { return };
|
&mut self,
|
||||||
let mut prev_id = self.add_system_inner(prev).unwrap();
|
configs: SystemConfigs,
|
||||||
for next in system_iter {
|
ancestor_chained: bool,
|
||||||
let next_id = self.add_system_inner(next).unwrap();
|
) -> AddSystemsInnerResult {
|
||||||
self.dependency.graph.add_edge(prev_id, next_id, ());
|
match configs {
|
||||||
prev_id = next_id;
|
SystemConfigs::SystemConfig(config) => {
|
||||||
|
let node_id = self.add_system_inner(config).unwrap();
|
||||||
|
if ancestor_chained {
|
||||||
|
AddSystemsInnerResult {
|
||||||
|
densely_chained: true,
|
||||||
|
nodes: vec![node_id],
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AddSystemsInnerResult {
|
||||||
|
densely_chained: true,
|
||||||
|
nodes: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
SystemConfigs::Configs { configs, chained } => {
|
||||||
for system in system_iter {
|
let mut config_iter = configs.into_iter();
|
||||||
self.add_system_inner(system).unwrap();
|
let mut nodes_in_scope = Vec::new();
|
||||||
|
let mut densely_chained = true;
|
||||||
|
if chained {
|
||||||
|
let Some(prev) = config_iter.next() else {
|
||||||
|
return AddSystemsInnerResult {
|
||||||
|
nodes: Vec::new(),
|
||||||
|
densely_chained: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut previous_result = self.add_systems_inner(prev, true);
|
||||||
|
densely_chained = previous_result.densely_chained;
|
||||||
|
for current in config_iter {
|
||||||
|
let current_result = self.add_systems_inner(current, true);
|
||||||
|
densely_chained = densely_chained && current_result.densely_chained;
|
||||||
|
match (
|
||||||
|
previous_result.densely_chained,
|
||||||
|
current_result.densely_chained,
|
||||||
|
) {
|
||||||
|
// Both groups are "densely" chained, so we can simplify the graph by only
|
||||||
|
// chaining the last in the previous list to the first in the current list
|
||||||
|
(true, true) => {
|
||||||
|
let last_in_prev = previous_result.nodes.last().unwrap();
|
||||||
|
let first_in_current = current_result.nodes.first().unwrap();
|
||||||
|
self.dependency.graph.add_edge(
|
||||||
|
*last_in_prev,
|
||||||
|
*first_in_current,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// The previous group is "densely" chained, so we can simplify the graph by only
|
||||||
|
// chaining the last item from the previous list to every item in the current list
|
||||||
|
(true, false) => {
|
||||||
|
let last_in_prev = previous_result.nodes.last().unwrap();
|
||||||
|
for current_node in ¤t_result.nodes {
|
||||||
|
self.dependency.graph.add_edge(
|
||||||
|
*last_in_prev,
|
||||||
|
*current_node,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The current list is currently "densely" chained, so we can simplify the graph by
|
||||||
|
// only chaining every item in the previous list to the first item in the current list
|
||||||
|
(false, true) => {
|
||||||
|
let first_in_current = current_result.nodes.first().unwrap();
|
||||||
|
for previous_node in &previous_result.nodes {
|
||||||
|
self.dependency.graph.add_edge(
|
||||||
|
*previous_node,
|
||||||
|
*first_in_current,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Neither of the lists are "densely" chained, so we must chain every item in the first
|
||||||
|
// list to every item in the second list
|
||||||
|
(false, false) => {
|
||||||
|
for previous_node in &previous_result.nodes {
|
||||||
|
for current_node in ¤t_result.nodes {
|
||||||
|
self.dependency.graph.add_edge(
|
||||||
|
*previous_node,
|
||||||
|
*current_node,
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ancestor_chained {
|
||||||
|
nodes_in_scope.append(&mut previous_result.nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
previous_result = current_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure the last config's nodes are added
|
||||||
|
if ancestor_chained {
|
||||||
|
nodes_in_scope.append(&mut previous_result.nodes);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let more_than_one_entry = config_iter.len() > 1;
|
||||||
|
for config in config_iter {
|
||||||
|
let result = self.add_systems_inner(config, ancestor_chained);
|
||||||
|
densely_chained = densely_chained && result.densely_chained;
|
||||||
|
if ancestor_chained {
|
||||||
|
nodes_in_scope.extend(result.nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// an "unchained" SystemConfig is only densely chained if it has exactly one densely chained entry
|
||||||
|
if more_than_one_entry {
|
||||||
|
densely_chained = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddSystemsInnerResult {
|
||||||
|
nodes: nodes_in_scope,
|
||||||
|
densely_chained,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_system<M>(&mut self, system: impl IntoSystemConfig<M>) {
|
fn add_system_inner(&mut self, config: SystemConfig) -> Result<NodeId, ScheduleBuildError> {
|
||||||
self.add_system_inner(system).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_system_inner<M>(
|
|
||||||
&mut self,
|
|
||||||
system: impl IntoSystemConfig<M>,
|
|
||||||
) -> Result<NodeId, ScheduleBuildError> {
|
|
||||||
let SystemConfig {
|
|
||||||
system,
|
|
||||||
graph_info,
|
|
||||||
conditions,
|
|
||||||
} = system.into_config();
|
|
||||||
|
|
||||||
let id = NodeId::System(self.systems.len());
|
let id = NodeId::System(self.systems.len());
|
||||||
|
|
||||||
// graph updates are immediate
|
// graph updates are immediate
|
||||||
self.update_graphs(id, graph_info, false)?;
|
self.update_graphs(id, config.graph_info)?;
|
||||||
|
|
||||||
// system init has to be deferred (need `&mut World`)
|
// system init has to be deferred (need `&mut World`)
|
||||||
self.uninit.push((id, 0));
|
self.uninit.push((id, 0));
|
||||||
self.systems.push(SystemNode::new(system));
|
self.systems.push(SystemNode::new(config.system));
|
||||||
self.system_conditions.push(Some(conditions));
|
self.system_conditions.push(Some(config.conditions));
|
||||||
|
|
||||||
Ok(id)
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
@ -639,7 +682,7 @@ impl ScheduleGraph {
|
||||||
};
|
};
|
||||||
|
|
||||||
// graph updates are immediate
|
// graph updates are immediate
|
||||||
self.update_graphs(id, graph_info, set.is_base())?;
|
self.update_graphs(id, graph_info)?;
|
||||||
|
|
||||||
// system init has to be deferred (need `&mut World`)
|
// system init has to be deferred (need `&mut World`)
|
||||||
let system_set_conditions =
|
let system_set_conditions =
|
||||||
|
@ -724,7 +767,6 @@ impl ScheduleGraph {
|
||||||
&mut self,
|
&mut self,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
graph_info: GraphInfo,
|
graph_info: GraphInfo,
|
||||||
is_base_set: bool,
|
|
||||||
) -> Result<(), ScheduleBuildError> {
|
) -> Result<(), ScheduleBuildError> {
|
||||||
self.check_sets(&id, &graph_info)?;
|
self.check_sets(&id, &graph_info)?;
|
||||||
self.check_edges(&id, &graph_info)?;
|
self.check_edges(&id, &graph_info)?;
|
||||||
|
@ -734,8 +776,6 @@ impl ScheduleGraph {
|
||||||
sets,
|
sets,
|
||||||
dependencies,
|
dependencies,
|
||||||
ambiguous_with,
|
ambiguous_with,
|
||||||
base_set,
|
|
||||||
add_default_base_set,
|
|
||||||
..
|
..
|
||||||
} = graph_info;
|
} = graph_info;
|
||||||
|
|
||||||
|
@ -749,30 +789,6 @@ impl ScheduleGraph {
|
||||||
self.dependency.graph.add_node(set);
|
self.dependency.graph.add_node(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the current node is not a base set, set the base set if it was configured
|
|
||||||
if !is_base_set {
|
|
||||||
if let Some(base_set) = base_set {
|
|
||||||
let set_id = self.system_set_ids[&base_set];
|
|
||||||
self.hierarchy.graph.add_edge(set_id, id, ());
|
|
||||||
} else if let Some(default_base_set) = &self.default_base_set {
|
|
||||||
if add_default_base_set {
|
|
||||||
match id {
|
|
||||||
NodeId::System(_) => {
|
|
||||||
// Queue the default base set. We queue systems instead of adding directly to allow
|
|
||||||
// sets to define base sets, which will override the default inheritance behavior
|
|
||||||
self.maybe_default_base_set.push(id);
|
|
||||||
}
|
|
||||||
NodeId::Set(_) => {
|
|
||||||
// Sets should be added automatically because developers explicitly called
|
|
||||||
// in_default_base_set()
|
|
||||||
let set_id = self.system_set_ids[default_base_set];
|
|
||||||
self.hierarchy.graph.add_edge(set_id, id, ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.dependency.graph.contains_node(id) {
|
if !self.dependency.graph.contains_node(id) {
|
||||||
self.dependency.graph.add_node(id);
|
self.dependency.graph.add_node(id);
|
||||||
}
|
}
|
||||||
|
@ -832,149 +848,15 @@ impl ScheduleGraph {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the base set for each node and caches the results on the node
|
|
||||||
fn calculate_base_sets_and_detect_cycles(&mut self) -> Result<(), ScheduleBuildError> {
|
|
||||||
let set_ids = (0..self.system_sets.len()).map(NodeId::Set);
|
|
||||||
let system_ids = (0..self.systems.len()).map(NodeId::System);
|
|
||||||
let mut visited_sets = vec![false; self.system_sets.len()];
|
|
||||||
// reset base set membership, as this can change when the schedule updates
|
|
||||||
for system in &mut self.systems {
|
|
||||||
system.base_set_membership = BaseSetMembership::Uncalculated;
|
|
||||||
}
|
|
||||||
for system_set in &mut self.system_sets {
|
|
||||||
system_set.base_set_membership = BaseSetMembership::Uncalculated;
|
|
||||||
}
|
|
||||||
for node_id in set_ids.chain(system_ids) {
|
|
||||||
Self::calculate_base_set(
|
|
||||||
&self.hierarchy,
|
|
||||||
&mut self.system_sets,
|
|
||||||
&mut self.systems,
|
|
||||||
&mut visited_sets,
|
|
||||||
node_id,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calculate_base_set(
|
|
||||||
hierarchy: &Dag,
|
|
||||||
system_sets: &mut [SystemSetNode],
|
|
||||||
systems: &mut [SystemNode],
|
|
||||||
visited_sets: &mut [bool],
|
|
||||||
node_id: NodeId,
|
|
||||||
) -> Result<Option<NodeId>, ScheduleBuildError> {
|
|
||||||
let base_set_membership = match node_id {
|
|
||||||
// systems only have
|
|
||||||
NodeId::System(_) => BaseSetMembership::Uncalculated,
|
|
||||||
NodeId::Set(index) => {
|
|
||||||
let set_node = &mut system_sets[index];
|
|
||||||
if set_node.inner.is_base() {
|
|
||||||
set_node.base_set_membership = BaseSetMembership::Some(node_id);
|
|
||||||
}
|
|
||||||
set_node.base_set_membership
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let base_set = match base_set_membership {
|
|
||||||
BaseSetMembership::None => None,
|
|
||||||
BaseSetMembership::Some(node_id) => Some(node_id),
|
|
||||||
BaseSetMembership::Uncalculated => {
|
|
||||||
let mut base_set: Option<NodeId> = None;
|
|
||||||
if let NodeId::Set(index) = node_id {
|
|
||||||
if visited_sets[index] {
|
|
||||||
return Err(ScheduleBuildError::HierarchyCycle);
|
|
||||||
}
|
|
||||||
visited_sets[index] = true;
|
|
||||||
}
|
|
||||||
for neighbor in hierarchy
|
|
||||||
.graph
|
|
||||||
.neighbors_directed(node_id, Direction::Incoming)
|
|
||||||
{
|
|
||||||
if let Some(calculated_base_set) = Self::calculate_base_set(
|
|
||||||
hierarchy,
|
|
||||||
system_sets,
|
|
||||||
systems,
|
|
||||||
visited_sets,
|
|
||||||
neighbor,
|
|
||||||
)? {
|
|
||||||
if let Some(first_set) = base_set {
|
|
||||||
if first_set != calculated_base_set {
|
|
||||||
return Err(match node_id {
|
|
||||||
NodeId::System(index) => {
|
|
||||||
ScheduleBuildError::SystemInMultipleBaseSets {
|
|
||||||
system: systems[index].name(),
|
|
||||||
first_set: system_sets[first_set.index()].name(),
|
|
||||||
second_set: system_sets[calculated_base_set.index()]
|
|
||||||
.name(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NodeId::Set(index) => {
|
|
||||||
ScheduleBuildError::SetInMultipleBaseSets {
|
|
||||||
set: system_sets[index].name(),
|
|
||||||
first_set: system_sets[first_set.index()].name(),
|
|
||||||
second_set: system_sets[calculated_base_set.index()]
|
|
||||||
.name(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
base_set = Some(calculated_base_set);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match node_id {
|
|
||||||
NodeId::System(index) => {
|
|
||||||
systems[index].base_set_membership = if let Some(base_set) = base_set {
|
|
||||||
BaseSetMembership::Some(base_set)
|
|
||||||
} else {
|
|
||||||
BaseSetMembership::None
|
|
||||||
};
|
|
||||||
}
|
|
||||||
NodeId::Set(index) => {
|
|
||||||
system_sets[index].base_set_membership = if let Some(base_set) = base_set {
|
|
||||||
BaseSetMembership::Some(base_set)
|
|
||||||
} else {
|
|
||||||
BaseSetMembership::None
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
base_set
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(base_set)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build a [`SystemSchedule`] optimized for scheduler access from the [`ScheduleGraph`].
|
/// Build a [`SystemSchedule`] optimized for scheduler access from the [`ScheduleGraph`].
|
||||||
///
|
///
|
||||||
/// This method also
|
/// This method also
|
||||||
/// - calculates [`BaseSetMembership`]
|
|
||||||
/// - checks for dependency or hierarchy cycles
|
/// - checks for dependency or hierarchy cycles
|
||||||
/// - checks for system access conflicts and reports ambiguities
|
/// - checks for system access conflicts and reports ambiguities
|
||||||
pub fn build_schedule(
|
pub fn build_schedule(
|
||||||
&mut self,
|
&mut self,
|
||||||
components: &Components,
|
components: &Components,
|
||||||
) -> Result<SystemSchedule, ScheduleBuildError> {
|
) -> Result<SystemSchedule, ScheduleBuildError> {
|
||||||
self.calculate_base_sets_and_detect_cycles()?;
|
|
||||||
|
|
||||||
// Add missing base set membership to systems that defaulted to using the
|
|
||||||
// default base set and weren't added to a set that belongs to a base set.
|
|
||||||
if let Some(default_base_set) = &self.default_base_set {
|
|
||||||
let default_set_id = self.system_set_ids[default_base_set];
|
|
||||||
for system_id in std::mem::take(&mut self.maybe_default_base_set) {
|
|
||||||
let system_node = &mut self.systems[system_id.index()];
|
|
||||||
if system_node.base_set_membership == BaseSetMembership::None {
|
|
||||||
self.hierarchy.graph.add_edge(default_set_id, system_id, ());
|
|
||||||
system_node.base_set_membership = BaseSetMembership::Some(default_set_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_assert_ne!(
|
|
||||||
system_node.base_set_membership,
|
|
||||||
BaseSetMembership::Uncalculated,
|
|
||||||
"base set membership should have been calculated"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check hierarchy for cycles
|
// check hierarchy for cycles
|
||||||
self.hierarchy.topsort = self
|
self.hierarchy.topsort = self
|
||||||
.topsort_graph(&self.hierarchy.graph, ReportCycles::Hierarchy)
|
.topsort_graph(&self.hierarchy.graph, ReportCycles::Hierarchy)
|
||||||
|
@ -1340,17 +1222,14 @@ impl ScheduleGraph {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn set_default_base_set(&mut self, set: Option<BoxedSystemSet>) {
|
/// Values returned by `ScheduleGraph::add_systems_inner`
|
||||||
if let Some(set) = set {
|
struct AddSystemsInnerResult {
|
||||||
self.default_base_set = Some(set.dyn_clone());
|
/// All nodes contained inside this add_systems_inner call's SystemConfigs hierarchy
|
||||||
if self.system_set_ids.get(&set).is_none() {
|
nodes: Vec<NodeId>,
|
||||||
self.add_set(set);
|
/// True if and only if all nodes are "densely chained"
|
||||||
}
|
densely_chained: bool,
|
||||||
} else {
|
|
||||||
self.default_base_set = None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to select the appropriate reporting function.
|
/// Used to select the appropriate reporting function.
|
||||||
|
|
|
@ -23,34 +23,10 @@ pub trait SystemSet: DynHash + Debug + Send + Sync + 'static {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this set is a "base system set". Systems
|
|
||||||
/// can only belong to one base set at a time. Systems and Sets
|
|
||||||
/// can only be added to base sets using specialized `in_base_set`
|
|
||||||
/// APIs. This enables "mutually exclusive" behaviors. It also
|
|
||||||
/// enables schedules to have a "default base set", which can be used
|
|
||||||
/// to apply default configuration to systems.
|
|
||||||
fn is_base(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a boxed clone of the label corresponding to this system set.
|
/// Creates a boxed clone of the label corresponding to this system set.
|
||||||
fn dyn_clone(&self) -> Box<dyn SystemSet>;
|
fn dyn_clone(&self) -> Box<dyn SystemSet>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A marker trait for `SystemSet` types where [`is_base`] returns `true`.
|
|
||||||
/// This should only be implemented for types that satisfy this requirement.
|
|
||||||
/// It is automatically implemented for base set types by `#[derive(SystemSet)]`.
|
|
||||||
///
|
|
||||||
/// [`is_base`]: SystemSet::is_base
|
|
||||||
pub trait BaseSystemSet: SystemSet {}
|
|
||||||
|
|
||||||
/// A marker trait for `SystemSet` types where [`is_base`] returns `false`.
|
|
||||||
/// This should only be implemented for types that satisfy this requirement.
|
|
||||||
/// It is automatically implemented for non-base set types by `#[derive(SystemSet)]`.
|
|
||||||
///
|
|
||||||
/// [`is_base`]: SystemSet::is_base
|
|
||||||
pub trait FreeSystemSet: SystemSet {}
|
|
||||||
|
|
||||||
impl PartialEq for dyn SystemSet {
|
impl PartialEq for dyn SystemSet {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.dyn_eq(other.as_dyn_eq())
|
self.dyn_eq(other.as_dyn_eq())
|
||||||
|
|
|
@ -50,7 +50,7 @@ use super::{ReadOnlySystem, System};
|
||||||
/// # world.init_resource::<RanFlag>();
|
/// # world.init_resource::<RanFlag>();
|
||||||
/// #
|
/// #
|
||||||
/// # let mut app = Schedule::new();
|
/// # let mut app = Schedule::new();
|
||||||
/// app.add_system(my_system.run_if(Xor::new(
|
/// app.add_systems(my_system.run_if(Xor::new(
|
||||||
/// IntoSystem::into_system(resource_equals(A(1))),
|
/// IntoSystem::into_system(resource_equals(A(1))),
|
||||||
/// IntoSystem::into_system(resource_equals(B(1))),
|
/// IntoSystem::into_system(resource_equals(B(1))),
|
||||||
/// // The name of the combined system.
|
/// // The name of the combined system.
|
||||||
|
|
|
@ -582,9 +582,9 @@ impl<'w, 's> Commands<'w, 's> {
|
||||||
/// # world.init_resource::<Counter>();
|
/// # world.init_resource::<Counter>();
|
||||||
/// #
|
/// #
|
||||||
/// # let mut setup_schedule = Schedule::new();
|
/// # let mut setup_schedule = Schedule::new();
|
||||||
/// # setup_schedule.add_system(setup);
|
/// # setup_schedule.add_systems(setup);
|
||||||
/// # let mut assert_schedule = Schedule::new();
|
/// # let mut assert_schedule = Schedule::new();
|
||||||
/// # assert_schedule.add_system(assert_names);
|
/// # assert_schedule.add_systems(assert_names);
|
||||||
/// #
|
/// #
|
||||||
/// # setup_schedule.run(&mut world);
|
/// # setup_schedule.run(&mut world);
|
||||||
/// # assert_schedule.run(&mut world);
|
/// # assert_schedule.run(&mut world);
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
//!
|
//!
|
||||||
//! // Configure this system to run in between the other two systems
|
//! // Configure this system to run in between the other two systems
|
||||||
//! // using explicit dependencies.
|
//! // using explicit dependencies.
|
||||||
//! schedule.add_system(print_mid.after(print_first).before(print_last));
|
//! schedule.add_systems(print_mid.after(print_first).before(print_last));
|
||||||
//! // Prints "Hello, World!"
|
//! // Prints "Hello, World!"
|
||||||
//! schedule.run(&mut world);
|
//! schedule.run(&mut world);
|
||||||
//!
|
//!
|
||||||
|
@ -214,7 +214,7 @@ mod tests {
|
||||||
|
|
||||||
fn run_system<Marker, S: IntoSystem<(), (), Marker>>(world: &mut World, system: S) {
|
fn run_system<Marker, S: IntoSystem<(), (), Marker>>(world: &mut World, system: S) {
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
schedule.add_system(system);
|
schedule.add_systems(system);
|
||||||
schedule.run(world);
|
schedule.run(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use std::borrow::Cow;
|
||||||
///
|
///
|
||||||
/// Systems are executed in parallel, in opportunistic order; data access is managed automatically.
|
/// Systems are executed in parallel, in opportunistic order; data access is managed automatically.
|
||||||
/// It's possible to specify explicit execution order between specific systems,
|
/// It's possible to specify explicit execution order between specific systems,
|
||||||
/// see [`IntoSystemConfig`](crate::schedule::IntoSystemConfig).
|
/// see [`IntoSystemConfigs`](crate::schedule::IntoSystemConfigs).
|
||||||
pub trait System: Send + Sync + 'static {
|
pub trait System: Send + Sync + 'static {
|
||||||
/// The system's input. See [`In`](crate::system::In) for
|
/// The system's input. See [`In`](crate::system::In) for
|
||||||
/// [`FunctionSystem`](crate::system::FunctionSystem)s.
|
/// [`FunctionSystem`](crate::system::FunctionSystem)s.
|
||||||
|
|
|
@ -674,7 +674,7 @@ unsafe impl SystemParam for &'_ World {
|
||||||
/// move |mut val| val.0 = value.0
|
/// move |mut val| val.0 = value.0
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // .add_system(reset_to_system(my_config))
|
/// // .add_systems(reset_to_system(my_config))
|
||||||
/// # assert_is_system(reset_to_system(Config(10)));
|
/// # assert_is_system(reset_to_system(Config(10)));
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T);
|
pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T);
|
||||||
|
|
|
@ -138,7 +138,7 @@ pub mod adapter {
|
||||||
///
|
///
|
||||||
/// // Building a new schedule/app...
|
/// // Building a new schedule/app...
|
||||||
/// let mut sched = Schedule::default();
|
/// let mut sched = Schedule::default();
|
||||||
/// sched.add_system(
|
/// sched.add_systems(
|
||||||
/// // Panic if the load system returns an error.
|
/// // Panic if the load system returns an error.
|
||||||
/// load_save_system.pipe(system_adapter::unwrap)
|
/// load_save_system.pipe(system_adapter::unwrap)
|
||||||
/// )
|
/// )
|
||||||
|
@ -169,7 +169,7 @@ pub mod adapter {
|
||||||
///
|
///
|
||||||
/// // Building a new schedule/app...
|
/// // Building a new schedule/app...
|
||||||
/// let mut sched = Schedule::default();
|
/// let mut sched = Schedule::default();
|
||||||
/// sched.add_system(
|
/// sched.add_systems(
|
||||||
/// // Prints system information.
|
/// // Prints system information.
|
||||||
/// data_pipe_system.pipe(system_adapter::info)
|
/// data_pipe_system.pipe(system_adapter::info)
|
||||||
/// )
|
/// )
|
||||||
|
@ -196,7 +196,7 @@ pub mod adapter {
|
||||||
///
|
///
|
||||||
/// // Building a new schedule/app...
|
/// // Building a new schedule/app...
|
||||||
/// let mut sched = Schedule::default();
|
/// let mut sched = Schedule::default();
|
||||||
/// sched.add_system(
|
/// sched.add_systems(
|
||||||
/// // Prints debug data from system.
|
/// // Prints debug data from system.
|
||||||
/// parse_message_system.pipe(system_adapter::dbg)
|
/// parse_message_system.pipe(system_adapter::dbg)
|
||||||
/// )
|
/// )
|
||||||
|
@ -223,7 +223,7 @@ pub mod adapter {
|
||||||
///
|
///
|
||||||
/// // Building a new schedule/app...
|
/// // Building a new schedule/app...
|
||||||
/// # let mut sched = Schedule::default();
|
/// # let mut sched = Schedule::default();
|
||||||
/// sched.add_system(
|
/// sched.add_systems(
|
||||||
/// // Prints system warning if system returns an error.
|
/// // Prints system warning if system returns an error.
|
||||||
/// warning_pipe_system.pipe(system_adapter::warn)
|
/// warning_pipe_system.pipe(system_adapter::warn)
|
||||||
/// )
|
/// )
|
||||||
|
@ -251,7 +251,7 @@ pub mod adapter {
|
||||||
/// use bevy_ecs::prelude::*;
|
/// use bevy_ecs::prelude::*;
|
||||||
/// // Building a new schedule/app...
|
/// // Building a new schedule/app...
|
||||||
/// let mut sched = Schedule::default();
|
/// let mut sched = Schedule::default();
|
||||||
/// sched.add_system(
|
/// sched.add_systems(
|
||||||
/// // Prints system error if system fails.
|
/// // Prints system error if system fails.
|
||||||
/// parse_error_message_system.pipe(system_adapter::error)
|
/// parse_error_message_system.pipe(system_adapter::error)
|
||||||
/// )
|
/// )
|
||||||
|
@ -287,7 +287,7 @@ pub mod adapter {
|
||||||
///
|
///
|
||||||
/// // Building a new schedule/app...
|
/// // Building a new schedule/app...
|
||||||
/// # let mut sched = Schedule::default(); sched
|
/// # let mut sched = Schedule::default(); sched
|
||||||
/// .add_system(
|
/// .add_systems(
|
||||||
/// // If the system fails, just move on and try again next frame.
|
/// // If the system fails, just move on and try again next frame.
|
||||||
/// fallible_system.pipe(system_adapter::ignore)
|
/// fallible_system.pipe(system_adapter::ignore)
|
||||||
/// )
|
/// )
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod converter;
|
mod converter;
|
||||||
mod gilrs_system;
|
mod gilrs_system;
|
||||||
|
|
||||||
use bevy_app::{App, CoreSet, Plugin, StartupSet};
|
use bevy_app::{App, Plugin, PreStartup, PreUpdate};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_input::InputSystem;
|
use bevy_input::InputSystem;
|
||||||
use bevy_utils::tracing::error;
|
use bevy_utils::tracing::error;
|
||||||
|
@ -20,14 +20,8 @@ impl Plugin for GilrsPlugin {
|
||||||
{
|
{
|
||||||
Ok(gilrs) => {
|
Ok(gilrs) => {
|
||||||
app.insert_non_send_resource(gilrs)
|
app.insert_non_send_resource(gilrs)
|
||||||
.add_startup_system(
|
.add_systems(PreStartup, gilrs_event_startup_system)
|
||||||
gilrs_event_startup_system.in_base_set(StartupSet::PreStartup),
|
.add_systems(PreUpdate, gilrs_event_system.before(InputSystem));
|
||||||
)
|
|
||||||
.add_system(
|
|
||||||
gilrs_event_system
|
|
||||||
.before(InputSystem)
|
|
||||||
.in_base_set(CoreSet::PreUpdate),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Err(err) => error!("Failed to start Gilrs. {}", err),
|
Err(err) => error!("Failed to start Gilrs. {}", err),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use bevy_app::{App, CoreSet, Plugin};
|
use bevy_app::{App, Last, Plugin};
|
||||||
use bevy_core::Name;
|
use bevy_core::Name;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_log::warn;
|
use bevy_log::warn;
|
||||||
|
@ -96,10 +96,10 @@ impl<T: Component> Default for ValidParentCheckPlugin<T> {
|
||||||
|
|
||||||
impl<T: Component> Plugin for ValidParentCheckPlugin<T> {
|
impl<T: Component> Plugin for ValidParentCheckPlugin<T> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<ReportHierarchyIssue<T>>().add_system(
|
app.init_resource::<ReportHierarchyIssue<T>>().add_systems(
|
||||||
|
Last,
|
||||||
check_hierarchy_component_has_valid_parent::<T>
|
check_hierarchy_component_has_valid_parent::<T>
|
||||||
.run_if(resource_equals(ReportHierarchyIssue::<T>::new(true)))
|
.run_if(resource_equals(ReportHierarchyIssue::<T>::new(true))),
|
||||||
.in_base_set(CoreSet::Last),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use std::hash::Hash;
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .add_plugins(DefaultPlugins)
|
/// .add_plugins(DefaultPlugins)
|
||||||
/// .add_system(pause_menu.run_if(input_toggle_active(false, KeyCode::Escape)))
|
/// .add_systems(Update, pause_menu.run_if(input_toggle_active(false, KeyCode::Escape)))
|
||||||
/// .run();
|
/// .run();
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
@ -33,7 +33,7 @@ use std::hash::Hash;
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .add_plugins(DefaultPlugins)
|
/// .add_plugins(DefaultPlugins)
|
||||||
/// .init_resource::<Paused>()
|
/// .init_resource::<Paused>()
|
||||||
/// .add_system(pause_menu.run_if(|paused: Res<Paused>| paused.0))
|
/// .add_systems(Update, pause_menu.run_if(|paused: Res<Paused>| paused.0))
|
||||||
/// .run();
|
/// .run();
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
@ -75,7 +75,7 @@ where
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .add_plugins(DefaultPlugins)
|
/// .add_plugins(DefaultPlugins)
|
||||||
/// .add_system(jump.run_if(input_just_pressed(KeyCode::Space)))
|
/// .add_systems(Update, jump.run_if(input_just_pressed(KeyCode::Space)))
|
||||||
/// .run();
|
/// .run();
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
|
|
|
@ -53,18 +53,18 @@ pub struct InputSystem;
|
||||||
|
|
||||||
impl Plugin for InputPlugin {
|
impl Plugin for InputPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.configure_set(InputSystem.in_base_set(CoreSet::PreUpdate))
|
app
|
||||||
// keyboard
|
// keyboard
|
||||||
.add_event::<KeyboardInput>()
|
.add_event::<KeyboardInput>()
|
||||||
.init_resource::<Input<KeyCode>>()
|
.init_resource::<Input<KeyCode>>()
|
||||||
.init_resource::<Input<ScanCode>>()
|
.init_resource::<Input<ScanCode>>()
|
||||||
.add_system(keyboard_input_system.in_set(InputSystem))
|
.add_systems(PreUpdate, keyboard_input_system.in_set(InputSystem))
|
||||||
// mouse
|
// mouse
|
||||||
.add_event::<MouseButtonInput>()
|
.add_event::<MouseButtonInput>()
|
||||||
.add_event::<MouseMotion>()
|
.add_event::<MouseMotion>()
|
||||||
.add_event::<MouseWheel>()
|
.add_event::<MouseWheel>()
|
||||||
.init_resource::<Input<MouseButton>>()
|
.init_resource::<Input<MouseButton>>()
|
||||||
.add_system(mouse_button_input_system.in_set(InputSystem))
|
.add_systems(PreUpdate, mouse_button_input_system.in_set(InputSystem))
|
||||||
// gamepad
|
// gamepad
|
||||||
.add_event::<GamepadConnectionEvent>()
|
.add_event::<GamepadConnectionEvent>()
|
||||||
.add_event::<GamepadButtonChangedEvent>()
|
.add_event::<GamepadButtonChangedEvent>()
|
||||||
|
@ -76,6 +76,7 @@ impl Plugin for InputPlugin {
|
||||||
.init_resource::<Axis<GamepadAxis>>()
|
.init_resource::<Axis<GamepadAxis>>()
|
||||||
.init_resource::<Axis<GamepadButton>>()
|
.init_resource::<Axis<GamepadButton>>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
PreUpdate,
|
||||||
(
|
(
|
||||||
gamepad_event_system,
|
gamepad_event_system,
|
||||||
gamepad_connection_system.after(gamepad_event_system),
|
gamepad_connection_system.after(gamepad_event_system),
|
||||||
|
@ -91,7 +92,7 @@ impl Plugin for InputPlugin {
|
||||||
// touch
|
// touch
|
||||||
.add_event::<TouchInput>()
|
.add_event::<TouchInput>()
|
||||||
.init_resource::<Touches>()
|
.init_resource::<Touches>()
|
||||||
.add_system(touch_screen_input_system.in_set(InputSystem));
|
.add_systems(PreUpdate, touch_screen_input_system.in_set(InputSystem));
|
||||||
|
|
||||||
// Register common types
|
// Register common types
|
||||||
app.register_type::<ButtonState>();
|
app.register_type::<ButtonState>();
|
||||||
|
|
|
@ -55,7 +55,7 @@ use bevy_render::{
|
||||||
render_phase::sort_phase_system,
|
render_phase::sort_phase_system,
|
||||||
render_resource::Shader,
|
render_resource::Shader,
|
||||||
view::{ViewSet, VisibilitySystems},
|
view::{ViewSet, VisibilitySystems},
|
||||||
ExtractSchedule, RenderApp, RenderSet,
|
ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::TransformSystem;
|
use bevy_transform::TransformSystem;
|
||||||
use environment_map::EnvironmentMapPlugin;
|
use environment_map::EnvironmentMapPlugin;
|
||||||
|
@ -176,59 +176,58 @@ impl Plugin for PbrPlugin {
|
||||||
.init_resource::<PointLightShadowMap>()
|
.init_resource::<PointLightShadowMap>()
|
||||||
.add_plugin(ExtractResourcePlugin::<AmbientLight>::default())
|
.add_plugin(ExtractResourcePlugin::<AmbientLight>::default())
|
||||||
.configure_sets(
|
.configure_sets(
|
||||||
|
PostUpdate,
|
||||||
(
|
(
|
||||||
SimulationLightSystems::AddClusters,
|
SimulationLightSystems::AddClusters,
|
||||||
SimulationLightSystems::AddClustersFlush
|
SimulationLightSystems::AddClustersFlush,
|
||||||
.after(SimulationLightSystems::AddClusters)
|
|
||||||
.before(SimulationLightSystems::AssignLightsToClusters),
|
|
||||||
SimulationLightSystems::AssignLightsToClusters,
|
SimulationLightSystems::AssignLightsToClusters,
|
||||||
SimulationLightSystems::CheckLightVisibility,
|
|
||||||
SimulationLightSystems::UpdateDirectionalLightCascades,
|
|
||||||
SimulationLightSystems::UpdateLightFrusta,
|
|
||||||
)
|
)
|
||||||
.in_base_set(CoreSet::PostUpdate),
|
.chain(),
|
||||||
)
|
)
|
||||||
.add_plugin(FogPlugin)
|
.add_plugin(FogPlugin)
|
||||||
.add_systems((
|
.add_systems(
|
||||||
add_clusters.in_set(SimulationLightSystems::AddClusters),
|
PostUpdate,
|
||||||
apply_system_buffers.in_set(SimulationLightSystems::AddClustersFlush),
|
(
|
||||||
assign_lights_to_clusters
|
add_clusters.in_set(SimulationLightSystems::AddClusters),
|
||||||
.in_set(SimulationLightSystems::AssignLightsToClusters)
|
apply_system_buffers.in_set(SimulationLightSystems::AddClustersFlush),
|
||||||
.after(TransformSystem::TransformPropagate)
|
assign_lights_to_clusters
|
||||||
.after(VisibilitySystems::CheckVisibility)
|
.in_set(SimulationLightSystems::AssignLightsToClusters)
|
||||||
.after(CameraUpdateSystem),
|
.after(TransformSystem::TransformPropagate)
|
||||||
update_directional_light_cascades
|
.after(VisibilitySystems::CheckVisibility)
|
||||||
.in_set(SimulationLightSystems::UpdateDirectionalLightCascades)
|
.after(CameraUpdateSystem),
|
||||||
.after(TransformSystem::TransformPropagate)
|
update_directional_light_cascades
|
||||||
.after(CameraUpdateSystem),
|
.in_set(SimulationLightSystems::UpdateDirectionalLightCascades)
|
||||||
update_directional_light_frusta
|
.after(TransformSystem::TransformPropagate)
|
||||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
.after(CameraUpdateSystem),
|
||||||
// This must run after CheckVisibility because it relies on ComputedVisibility::is_visible()
|
update_directional_light_frusta
|
||||||
.after(VisibilitySystems::CheckVisibility)
|
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||||
.after(TransformSystem::TransformPropagate)
|
// This must run after CheckVisibility because it relies on ComputedVisibility::is_visible()
|
||||||
.after(SimulationLightSystems::UpdateDirectionalLightCascades)
|
.after(VisibilitySystems::CheckVisibility)
|
||||||
// We assume that no entity will be both a directional light and a spot light,
|
.after(TransformSystem::TransformPropagate)
|
||||||
// so these systems will run independently of one another.
|
.after(SimulationLightSystems::UpdateDirectionalLightCascades)
|
||||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
// We assume that no entity will be both a directional light and a spot light,
|
||||||
.ambiguous_with(update_spot_light_frusta),
|
// so these systems will run independently of one another.
|
||||||
update_point_light_frusta
|
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
.ambiguous_with(update_spot_light_frusta),
|
||||||
.after(TransformSystem::TransformPropagate)
|
update_point_light_frusta
|
||||||
.after(SimulationLightSystems::AssignLightsToClusters),
|
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||||
update_spot_light_frusta
|
.after(TransformSystem::TransformPropagate)
|
||||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
.after(SimulationLightSystems::AssignLightsToClusters),
|
||||||
.after(TransformSystem::TransformPropagate)
|
update_spot_light_frusta
|
||||||
.after(SimulationLightSystems::AssignLightsToClusters),
|
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||||
check_light_mesh_visibility
|
.after(TransformSystem::TransformPropagate)
|
||||||
.in_set(SimulationLightSystems::CheckLightVisibility)
|
.after(SimulationLightSystems::AssignLightsToClusters),
|
||||||
.after(VisibilitySystems::CalculateBoundsFlush)
|
check_light_mesh_visibility
|
||||||
.after(TransformSystem::TransformPropagate)
|
.in_set(SimulationLightSystems::CheckLightVisibility)
|
||||||
.after(SimulationLightSystems::UpdateLightFrusta)
|
.after(VisibilitySystems::CalculateBoundsFlush)
|
||||||
// NOTE: This MUST be scheduled AFTER the core renderer visibility check
|
.after(TransformSystem::TransformPropagate)
|
||||||
// because that resets entity ComputedVisibility for the first view
|
.after(SimulationLightSystems::UpdateLightFrusta)
|
||||||
// which would override any results from this otherwise
|
// NOTE: This MUST be scheduled AFTER the core renderer visibility check
|
||||||
.after(VisibilitySystems::CheckVisibility),
|
// because that resets entity ComputedVisibility for the first view
|
||||||
));
|
// which would override any results from this otherwise
|
||||||
|
.after(VisibilitySystems::CheckVisibility),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
app.world
|
app.world
|
||||||
.resource_mut::<Assets<StandardMaterial>>()
|
.resource_mut::<Assets<StandardMaterial>>()
|
||||||
|
@ -248,31 +247,39 @@ impl Plugin for PbrPlugin {
|
||||||
|
|
||||||
// Extract the required data from the main world
|
// Extract the required data from the main world
|
||||||
render_app
|
render_app
|
||||||
.configure_set(RenderLightSystems::PrepareLights.in_set(RenderSet::Prepare))
|
.configure_sets(
|
||||||
.configure_set(RenderLightSystems::PrepareClusters.in_set(RenderSet::Prepare))
|
Render,
|
||||||
.configure_set(RenderLightSystems::QueueShadows.in_set(RenderSet::Queue))
|
(
|
||||||
|
RenderLightSystems::PrepareLights.in_set(RenderSet::Prepare),
|
||||||
|
RenderLightSystems::PrepareClusters.in_set(RenderSet::Prepare),
|
||||||
|
RenderLightSystems::QueueShadows.in_set(RenderSet::Queue),
|
||||||
|
),
|
||||||
|
)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
ExtractSchedule,
|
||||||
(
|
(
|
||||||
render::extract_clusters.in_set(RenderLightSystems::ExtractClusters),
|
render::extract_clusters.in_set(RenderLightSystems::ExtractClusters),
|
||||||
render::extract_lights.in_set(RenderLightSystems::ExtractLights),
|
render::extract_lights.in_set(RenderLightSystems::ExtractLights),
|
||||||
)
|
),
|
||||||
.in_schedule(ExtractSchedule),
|
)
|
||||||
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
(
|
||||||
|
render::prepare_lights
|
||||||
|
.before(ViewSet::PrepareUniforms)
|
||||||
|
.in_set(RenderLightSystems::PrepareLights),
|
||||||
|
// A sync is needed after prepare_lights, before prepare_view_uniforms,
|
||||||
|
// because prepare_lights creates new views for shadow mapping
|
||||||
|
apply_system_buffers
|
||||||
|
.in_set(RenderSet::Prepare)
|
||||||
|
.after(RenderLightSystems::PrepareLights)
|
||||||
|
.before(ViewSet::PrepareUniforms),
|
||||||
|
render::prepare_clusters
|
||||||
|
.after(render::prepare_lights)
|
||||||
|
.in_set(RenderLightSystems::PrepareClusters),
|
||||||
|
sort_phase_system::<Shadow>.in_set(RenderSet::PhaseSort),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.add_systems((
|
|
||||||
render::prepare_lights
|
|
||||||
.before(ViewSet::PrepareUniforms)
|
|
||||||
.in_set(RenderLightSystems::PrepareLights),
|
|
||||||
// A sync is needed after prepare_lights, before prepare_view_uniforms,
|
|
||||||
// because prepare_lights creates new views for shadow mapping
|
|
||||||
apply_system_buffers
|
|
||||||
.in_set(RenderSet::Prepare)
|
|
||||||
.after(RenderLightSystems::PrepareLights)
|
|
||||||
.before(ViewSet::PrepareUniforms),
|
|
||||||
render::prepare_clusters
|
|
||||||
.after(render::prepare_lights)
|
|
||||||
.in_set(RenderLightSystems::PrepareClusters),
|
|
||||||
sort_phase_system::<Shadow>.in_set(RenderSet::PhaseSort),
|
|
||||||
))
|
|
||||||
.init_resource::<ShadowSamplers>()
|
.init_resource::<ShadowSamplers>()
|
||||||
.init_resource::<LightMeta>()
|
.init_resource::<LightMeta>()
|
||||||
.init_resource::<GlobalLightMeta>();
|
.init_resource::<GlobalLightMeta>();
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, SetMeshBindGroup,
|
MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, SetMeshBindGroup,
|
||||||
SetMeshViewBindGroup, Shadow,
|
SetMeshViewBindGroup, Shadow,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
core_3d::{AlphaMask3d, Opaque3d, Transparent3d},
|
core_3d::{AlphaMask3d, Opaque3d, Transparent3d},
|
||||||
|
@ -35,7 +35,7 @@ use bevy_render::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::FallbackImage,
|
texture::FallbackImage,
|
||||||
view::{ExtractedView, Msaa, VisibleEntities},
|
view::{ExtractedView, Msaa, VisibleEntities},
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_utils::{tracing::error, HashMap, HashSet};
|
use bevy_utils::{tracing::error, HashMap, HashSet};
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
@ -199,14 +199,17 @@ where
|
||||||
.init_resource::<ExtractedMaterials<M>>()
|
.init_resource::<ExtractedMaterials<M>>()
|
||||||
.init_resource::<RenderMaterials<M>>()
|
.init_resource::<RenderMaterials<M>>()
|
||||||
.init_resource::<SpecializedMeshPipelines<MaterialPipeline<M>>>()
|
.init_resource::<SpecializedMeshPipelines<MaterialPipeline<M>>>()
|
||||||
.add_systems((
|
.add_systems(ExtractSchedule, extract_materials::<M>)
|
||||||
extract_materials::<M>.in_schedule(ExtractSchedule),
|
.add_systems(
|
||||||
prepare_materials::<M>
|
Render,
|
||||||
.in_set(RenderSet::Prepare)
|
(
|
||||||
.after(PrepareAssetSet::PreAssetPrepare),
|
prepare_materials::<M>
|
||||||
render::queue_shadows::<M>.in_set(RenderLightSystems::QueueShadows),
|
.in_set(RenderSet::Prepare)
|
||||||
queue_material_meshes::<M>.in_set(RenderSet::Queue),
|
.after(PrepareAssetSet::PreAssetPrepare),
|
||||||
));
|
render::queue_shadows::<M>.in_set(RenderLightSystems::QueueShadows),
|
||||||
|
queue_material_meshes::<M>.in_set(RenderSet::Queue),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepassPipelinePlugin is required for shadow mapping and the optional PrepassPlugin
|
// PrepassPipelinePlugin is required for shadow mapping and the optional PrepassPlugin
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy_app::{IntoSystemAppConfig, Plugin};
|
use bevy_app::Plugin;
|
||||||
use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped};
|
use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped};
|
||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
prelude::Camera3d,
|
prelude::Camera3d,
|
||||||
|
@ -39,7 +39,7 @@ use bevy_render::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::{FallbackImagesDepth, FallbackImagesMsaa, TextureCache},
|
texture::{FallbackImagesDepth, FallbackImagesMsaa, TextureCache},
|
||||||
view::{ExtractedView, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities},
|
view::{ExtractedView, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities},
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_utils::{tracing::error, HashMap};
|
use bevy_utils::{tracing::error, HashMap};
|
||||||
|
|
||||||
|
@ -102,7 +102,10 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
render_app
|
render_app
|
||||||
.add_system(queue_prepass_view_bind_group::<M>.in_set(RenderSet::Queue))
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
queue_prepass_view_bind_group::<M>.in_set(RenderSet::Queue),
|
||||||
|
)
|
||||||
.init_resource::<PrepassPipeline<M>>()
|
.init_resource::<PrepassPipeline<M>>()
|
||||||
.init_resource::<PrepassViewBindGroup>()
|
.init_resource::<PrepassViewBindGroup>()
|
||||||
.init_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>();
|
.init_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>();
|
||||||
|
@ -130,15 +133,18 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
render_app
|
render_app
|
||||||
.add_systems((
|
.add_systems(ExtractSchedule, extract_camera_prepass_phase)
|
||||||
extract_camera_prepass_phase.in_schedule(ExtractSchedule),
|
.add_systems(
|
||||||
prepare_prepass_textures
|
Render,
|
||||||
.in_set(RenderSet::Prepare)
|
(
|
||||||
.after(bevy_render::view::prepare_windows),
|
prepare_prepass_textures
|
||||||
queue_prepass_material_meshes::<M>.in_set(RenderSet::Queue),
|
.in_set(RenderSet::Prepare)
|
||||||
sort_phase_system::<Opaque3dPrepass>.in_set(RenderSet::PhaseSort),
|
.after(bevy_render::view::prepare_windows),
|
||||||
sort_phase_system::<AlphaMask3dPrepass>.in_set(RenderSet::PhaseSort),
|
queue_prepass_material_meshes::<M>.in_set(RenderSet::Queue),
|
||||||
))
|
sort_phase_system::<Opaque3dPrepass>.in_set(RenderSet::PhaseSort),
|
||||||
|
sort_phase_system::<AlphaMask3dPrepass>.in_set(RenderSet::PhaseSort),
|
||||||
|
),
|
||||||
|
)
|
||||||
.init_resource::<DrawFunctions<Opaque3dPrepass>>()
|
.init_resource::<DrawFunctions<Opaque3dPrepass>>()
|
||||||
.init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
|
.init_resource::<DrawFunctions<AlphaMask3dPrepass>>()
|
||||||
.add_render_command::<Opaque3dPrepass, DrawPrepass<M>>()
|
.add_render_command::<Opaque3dPrepass, DrawPrepass<M>>()
|
||||||
|
|
|
@ -8,7 +8,7 @@ use bevy_render::{
|
||||||
render_resource::{DynamicUniformBuffer, Shader, ShaderType},
|
render_resource::{DynamicUniformBuffer, Shader, ShaderType},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
view::ExtractedView,
|
view::ExtractedView,
|
||||||
RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{FogFalloff, FogSettings};
|
use crate::{FogFalloff, FogSettings};
|
||||||
|
@ -142,8 +142,11 @@ impl Plugin for FogPlugin {
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<FogMeta>()
|
.init_resource::<FogMeta>()
|
||||||
.add_system(prepare_fog.in_set(RenderFogSystems::PrepareFog))
|
.add_systems(Render, prepare_fog.in_set(RenderFogSystems::PrepareFog))
|
||||||
.configure_set(RenderFogSystems::PrepareFog.in_set(RenderSet::Prepare));
|
.configure_set(
|
||||||
|
Render,
|
||||||
|
RenderFogSystems::PrepareFog.in_set(RenderSet::Prepare),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
ViewClusterBindings, ViewFogUniformOffset, ViewLightsUniformOffset, ViewShadowBindings,
|
ViewClusterBindings, ViewFogUniformOffset, ViewLightsUniformOffset, ViewShadowBindings,
|
||||||
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS,
|
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT, MAX_CASCADES_PER_LIGHT, MAX_DIRECTIONAL_LIGHTS,
|
||||||
};
|
};
|
||||||
use bevy_app::{IntoSystemAppConfigs, Plugin};
|
use bevy_app::Plugin;
|
||||||
use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped};
|
use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped};
|
||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
prepass::ViewPrepassTextures,
|
prepass::ViewPrepassTextures,
|
||||||
|
@ -36,7 +36,7 @@ use bevy_render::{
|
||||||
FallbackImagesMsaa, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
FallbackImagesMsaa, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
||||||
},
|
},
|
||||||
view::{ComputedVisibility, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms},
|
view::{ComputedVisibility, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms},
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
|
@ -107,12 +107,15 @@ impl Plugin for MeshRenderPlugin {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<MeshPipeline>()
|
.init_resource::<MeshPipeline>()
|
||||||
.init_resource::<SkinnedMeshUniform>()
|
.init_resource::<SkinnedMeshUniform>()
|
||||||
.add_systems((extract_meshes, extract_skinned_meshes).in_schedule(ExtractSchedule))
|
.add_systems(ExtractSchedule, (extract_meshes, extract_skinned_meshes))
|
||||||
.add_systems((
|
.add_systems(
|
||||||
prepare_skinned_meshes.in_set(RenderSet::Prepare),
|
Render,
|
||||||
queue_mesh_bind_group.in_set(RenderSet::Queue),
|
(
|
||||||
queue_mesh_view_bind_groups.in_set(RenderSet::Queue),
|
prepare_skinned_meshes.in_set(RenderSet::Prepare),
|
||||||
));
|
queue_mesh_bind_group.in_set(RenderSet::Queue),
|
||||||
|
queue_mesh_view_bind_groups.in_set(RenderSet::Queue),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use bevy_ecs::{prelude::*, reflect::ReflectComponent};
|
||||||
use bevy_reflect::std_traits::ReflectDefault;
|
use bevy_reflect::std_traits::ReflectDefault;
|
||||||
use bevy_reflect::{Reflect, TypeUuid};
|
use bevy_reflect::{Reflect, TypeUuid};
|
||||||
use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin};
|
use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin};
|
||||||
|
use bevy_render::Render;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
mesh::{Mesh, MeshVertexBufferLayout},
|
mesh::{Mesh, MeshVertexBufferLayout},
|
||||||
|
@ -47,7 +48,7 @@ impl Plugin for WireframePlugin {
|
||||||
.add_render_command::<Opaque3d, DrawWireframes>()
|
.add_render_command::<Opaque3d, DrawWireframes>()
|
||||||
.init_resource::<WireframePipeline>()
|
.init_resource::<WireframePipeline>()
|
||||||
.init_resource::<SpecializedMeshPipelines<WireframePipeline>>()
|
.init_resource::<SpecializedMeshPipelines<WireframePipeline>>()
|
||||||
.add_system(queue_wireframes.in_set(RenderSet::Queue));
|
.add_systems(Render, queue_wireframes.in_set(RenderSet::Queue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -492,7 +492,7 @@ impl NormalizedRenderTarget {
|
||||||
/// The system function is generic over the camera projection type, and only instances of
|
/// The system function is generic over the camera projection type, and only instances of
|
||||||
/// [`OrthographicProjection`] and [`PerspectiveProjection`] are automatically added to
|
/// [`OrthographicProjection`] and [`PerspectiveProjection`] are automatically added to
|
||||||
/// the app, as well as the runtime-selected [`Projection`].
|
/// the app, as well as the runtime-selected [`Projection`].
|
||||||
/// The system runs during [`CoreSet::PostUpdate`].
|
/// The system runs during [`PostUpdate`](bevy_app::PostUpdate).
|
||||||
///
|
///
|
||||||
/// ## World Resources
|
/// ## World Resources
|
||||||
///
|
///
|
||||||
|
@ -502,7 +502,6 @@ impl NormalizedRenderTarget {
|
||||||
/// [`OrthographicProjection`]: crate::camera::OrthographicProjection
|
/// [`OrthographicProjection`]: crate::camera::OrthographicProjection
|
||||||
/// [`PerspectiveProjection`]: crate::camera::PerspectiveProjection
|
/// [`PerspectiveProjection`]: crate::camera::PerspectiveProjection
|
||||||
/// [`Projection`]: crate::camera::Projection
|
/// [`Projection`]: crate::camera::Projection
|
||||||
/// [`CoreSet::PostUpdate`]: bevy_app::CoreSet::PostUpdate
|
|
||||||
pub fn camera_system<T: CameraProjection + Component>(
|
pub fn camera_system<T: CameraProjection + Component>(
|
||||||
mut window_resized_events: EventReader<WindowResized>,
|
mut window_resized_events: EventReader<WindowResized>,
|
||||||
mut window_created_events: EventReader<WindowCreated>,
|
mut window_created_events: EventReader<WindowCreated>,
|
||||||
|
|
|
@ -7,9 +7,9 @@ pub use camera::*;
|
||||||
pub use camera_driver_node::*;
|
pub use camera_driver_node::*;
|
||||||
pub use projection::*;
|
pub use projection::*;
|
||||||
|
|
||||||
use crate::{render_graph::RenderGraph, ExtractSchedule, RenderApp, RenderSet};
|
use crate::{render_graph::RenderGraph, ExtractSchedule, Render, RenderApp, RenderSet};
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::schedule::IntoSystemConfig;
|
use bevy_ecs::schedule::IntoSystemConfigs;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CameraPlugin;
|
pub struct CameraPlugin;
|
||||||
|
@ -29,8 +29,8 @@ impl Plugin for CameraPlugin {
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<SortedCameras>()
|
.init_resource::<SortedCameras>()
|
||||||
.add_system(extract_cameras.in_schedule(ExtractSchedule))
|
.add_systems(ExtractSchedule, extract_cameras)
|
||||||
.add_system(sort_cameras.in_set(RenderSet::Prepare));
|
.add_systems(Render, sort_cameras.in_set(RenderSet::Prepare));
|
||||||
let camera_driver_node = CameraDriverNode::new(&mut render_app.world);
|
let camera_driver_node = CameraDriverNode::new(&mut render_app.world);
|
||||||
let mut render_graph = render_app.world.resource_mut::<RenderGraph>();
|
let mut render_graph = render_app.world.resource_mut::<RenderGraph>();
|
||||||
render_graph.add_node(crate::main_graph::node::CAMERA_DRIVER, camera_driver_node);
|
render_graph.add_node(crate::main_graph::node::CAMERA_DRIVER, camera_driver_node);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use bevy_app::{App, CoreSchedule, CoreSet, IntoSystemAppConfig, Plugin, StartupSet};
|
use bevy_app::{App, Plugin, PostStartup, PostUpdate};
|
||||||
use bevy_ecs::{prelude::*, reflect::ReflectComponent};
|
use bevy_ecs::{prelude::*, reflect::ReflectComponent};
|
||||||
use bevy_math::{Mat4, Rect, Vec2};
|
use bevy_math::{Mat4, Rect, Vec2};
|
||||||
use bevy_reflect::{
|
use bevy_reflect::{
|
||||||
|
@ -27,25 +27,24 @@ pub struct CameraUpdateSystem;
|
||||||
impl<T: CameraProjection + Component + GetTypeRegistration> Plugin for CameraProjectionPlugin<T> {
|
impl<T: CameraProjection + Component + GetTypeRegistration> Plugin for CameraProjectionPlugin<T> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.register_type::<T>()
|
app.register_type::<T>()
|
||||||
.edit_schedule(CoreSchedule::Startup, |schedule| {
|
.add_systems(
|
||||||
schedule.configure_set(CameraUpdateSystem.in_base_set(StartupSet::PostStartup));
|
PostStartup,
|
||||||
})
|
|
||||||
.configure_set(CameraUpdateSystem.in_base_set(CoreSet::PostUpdate))
|
|
||||||
.add_systems((
|
|
||||||
crate::camera::camera_system::<T>
|
|
||||||
.on_startup()
|
|
||||||
.in_set(CameraUpdateSystem)
|
|
||||||
// We assume that each camera will only have one projection,
|
|
||||||
// so we can ignore ambiguities with all other monomorphizations.
|
|
||||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
|
||||||
.ambiguous_with(CameraUpdateSystem),
|
|
||||||
crate::camera::camera_system::<T>
|
crate::camera::camera_system::<T>
|
||||||
.in_set(CameraUpdateSystem)
|
.in_set(CameraUpdateSystem)
|
||||||
// We assume that each camera will only have one projection,
|
// We assume that each camera will only have one projection,
|
||||||
// so we can ignore ambiguities with all other monomorphizations.
|
// so we can ignore ambiguities with all other monomorphizations.
|
||||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||||
.ambiguous_with(CameraUpdateSystem),
|
.ambiguous_with(CameraUpdateSystem),
|
||||||
));
|
)
|
||||||
|
.add_systems(
|
||||||
|
PostUpdate,
|
||||||
|
crate::camera::camera_system::<T>
|
||||||
|
.in_set(CameraUpdateSystem)
|
||||||
|
// We assume that each camera will only have one projection,
|
||||||
|
// so we can ignore ambiguities with all other monomorphizations.
|
||||||
|
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||||
|
.ambiguous_with(CameraUpdateSystem),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ use crate::{
|
||||||
render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType},
|
render_resource::{encase::internal::WriteInto, DynamicUniformBuffer, ShaderType},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
view::ComputedVisibility,
|
view::ComputedVisibility,
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{Asset, Handle};
|
use bevy_asset::{Asset, Handle};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
|
@ -83,7 +83,10 @@ impl<C: Component + ShaderType + WriteInto + Clone> Plugin for UniformComponentP
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app
|
render_app
|
||||||
.insert_resource(ComponentUniforms::<C>::default())
|
.insert_resource(ComponentUniforms::<C>::default())
|
||||||
.add_system(prepare_uniform_components::<C>.in_set(RenderSet::Prepare));
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
prepare_uniform_components::<C>.in_set(RenderSet::Prepare),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,9 +183,9 @@ impl<C: ExtractComponent> Plugin for ExtractComponentPlugin<C> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
if self.only_extract_visible {
|
if self.only_extract_visible {
|
||||||
render_app.add_system(extract_visible_components::<C>.in_schedule(ExtractSchedule));
|
render_app.add_systems(ExtractSchedule, extract_visible_components::<C>);
|
||||||
} else {
|
} else {
|
||||||
render_app.add_system(extract_components::<C>.in_schedule(ExtractSchedule));
|
render_app.add_systems(ExtractSchedule, extract_components::<C>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
pub use bevy_render_macros::ExtractResource;
|
pub use bevy_render_macros::ExtractResource;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ impl<R: ExtractResource> Default for ExtractResourcePlugin<R> {
|
||||||
impl<R: ExtractResource> Plugin for ExtractResourcePlugin<R> {
|
impl<R: ExtractResource> Plugin for ExtractResourcePlugin<R> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app.add_system(extract_resource::<R>.in_schedule(ExtractSchedule));
|
render_app.add_systems(ExtractSchedule, extract_resource::<R>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ use crate::{
|
||||||
prelude::Shader,
|
prelude::Shader,
|
||||||
render_resource::{ShaderType, UniformBuffer},
|
render_resource::{ShaderType, UniformBuffer},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, IntoSystemAppConfigs, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{load_internal_asset, HandleUntyped};
|
use bevy_asset::{load_internal_asset, HandleUntyped};
|
||||||
use bevy_core::FrameCount;
|
use bevy_core::FrameCount;
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -26,8 +26,8 @@ impl Plugin for GlobalsPlugin {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<GlobalsBuffer>()
|
.init_resource::<GlobalsBuffer>()
|
||||||
.init_resource::<Time>()
|
.init_resource::<Time>()
|
||||||
.add_systems((extract_frame_count, extract_time).in_schedule(ExtractSchedule))
|
.add_systems(ExtractSchedule, (extract_frame_count, extract_time))
|
||||||
.add_system(prepare_globals_buffer.in_set(RenderSet::Prepare));
|
.add_systems(Render, prepare_globals_buffer.in_set(RenderSet::Prepare));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ use crate::{
|
||||||
settings::WgpuSettings,
|
settings::WgpuSettings,
|
||||||
view::{ViewPlugin, WindowRenderPlugin},
|
view::{ViewPlugin, WindowRenderPlugin},
|
||||||
};
|
};
|
||||||
use bevy_app::{App, AppLabel, CoreSchedule, Plugin, SubApp};
|
use bevy_app::{App, AppLabel, Plugin, SubApp};
|
||||||
use bevy_asset::{AddAsset, AssetServer};
|
use bevy_asset::{AddAsset, AssetServer};
|
||||||
use bevy_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState};
|
use bevy_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState};
|
||||||
use bevy_utils::tracing::debug;
|
use bevy_utils::tracing::debug;
|
||||||
|
@ -101,7 +101,11 @@ pub enum RenderSet {
|
||||||
CleanupFlush,
|
CleanupFlush,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderSet {
|
/// The main render schedule.
|
||||||
|
#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)]
|
||||||
|
pub struct Render;
|
||||||
|
|
||||||
|
impl Render {
|
||||||
/// Sets up the base structure of the rendering [`Schedule`].
|
/// Sets up the base structure of the rendering [`Schedule`].
|
||||||
///
|
///
|
||||||
/// The sets defined in this enum are configured to run in order,
|
/// The sets defined in this enum are configured to run in order,
|
||||||
|
@ -226,43 +230,38 @@ impl Plugin for RenderPlugin {
|
||||||
.insert_resource(render_adapter.clone())
|
.insert_resource(render_adapter.clone())
|
||||||
.init_resource::<ScratchMainWorld>();
|
.init_resource::<ScratchMainWorld>();
|
||||||
|
|
||||||
let pipeline_cache = PipelineCache::new(device.clone());
|
|
||||||
let asset_server = app.world.resource::<AssetServer>().clone();
|
|
||||||
|
|
||||||
let mut render_app = App::empty();
|
let mut render_app = App::empty();
|
||||||
render_app.add_simple_outer_schedule();
|
render_app.main_schedule_label = Box::new(Render);
|
||||||
let mut render_schedule = RenderSet::base_schedule();
|
|
||||||
|
|
||||||
// Prepare the schedule which extracts data from the main world to the render world
|
let mut extract_schedule = Schedule::new();
|
||||||
render_app.edit_schedule(ExtractSchedule, |schedule| {
|
extract_schedule.set_apply_final_buffers(false);
|
||||||
schedule
|
|
||||||
.set_apply_final_buffers(false)
|
|
||||||
.add_system(PipelineCache::extract_shaders);
|
|
||||||
});
|
|
||||||
|
|
||||||
// This set applies the commands from the extract stage while the render schedule
|
|
||||||
// is running in parallel with the main app.
|
|
||||||
render_schedule.add_system(apply_extract_commands.in_set(RenderSet::ExtractCommands));
|
|
||||||
|
|
||||||
render_schedule.add_system(
|
|
||||||
PipelineCache::process_pipeline_queue_system
|
|
||||||
.before(render_system)
|
|
||||||
.in_set(RenderSet::Render),
|
|
||||||
);
|
|
||||||
render_schedule.add_system(render_system.in_set(RenderSet::Render));
|
|
||||||
|
|
||||||
render_schedule.add_system(World::clear_entities.in_set(RenderSet::Cleanup));
|
|
||||||
|
|
||||||
render_app
|
render_app
|
||||||
.add_schedule(CoreSchedule::Main, render_schedule)
|
.add_schedule(ExtractSchedule, extract_schedule)
|
||||||
|
.add_schedule(Render, Render::base_schedule())
|
||||||
.init_resource::<render_graph::RenderGraph>()
|
.init_resource::<render_graph::RenderGraph>()
|
||||||
.insert_resource(RenderInstance(instance))
|
.insert_resource(RenderInstance(instance))
|
||||||
|
.insert_resource(PipelineCache::new(device.clone()))
|
||||||
.insert_resource(device)
|
.insert_resource(device)
|
||||||
.insert_resource(queue)
|
.insert_resource(queue)
|
||||||
.insert_resource(render_adapter)
|
.insert_resource(render_adapter)
|
||||||
.insert_resource(adapter_info)
|
.insert_resource(adapter_info)
|
||||||
.insert_resource(pipeline_cache)
|
.insert_resource(app.world.resource::<AssetServer>().clone())
|
||||||
.insert_resource(asset_server);
|
.add_systems(ExtractSchedule, PipelineCache::extract_shaders)
|
||||||
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
(
|
||||||
|
// This set applies the commands from the extract stage while the render schedule
|
||||||
|
// is running in parallel with the main app.
|
||||||
|
apply_extract_commands.in_set(RenderSet::ExtractCommands),
|
||||||
|
(
|
||||||
|
PipelineCache::process_pipeline_queue_system.before(render_system),
|
||||||
|
render_system,
|
||||||
|
)
|
||||||
|
.in_set(RenderSet::Render),
|
||||||
|
World::clear_entities.in_set(RenderSet::Cleanup),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
let (sender, receiver) = bevy_time::create_time_channels();
|
let (sender, receiver) = bevy_time::create_time_channels();
|
||||||
app.insert_resource(receiver);
|
app.insert_resource(receiver);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use async_channel::{Receiver, Sender};
|
use async_channel::{Receiver, Sender};
|
||||||
|
|
||||||
use bevy_app::{App, AppLabel, CoreSchedule, Plugin, SubApp};
|
use bevy_app::{App, AppLabel, Main, Plugin, SubApp};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
schedule::MainThreadExecutor,
|
schedule::MainThreadExecutor,
|
||||||
system::Resource,
|
system::Resource,
|
||||||
|
@ -72,8 +72,7 @@ impl Plugin for PipelinedRenderingPlugin {
|
||||||
app.insert_resource(MainThreadExecutor::new());
|
app.insert_resource(MainThreadExecutor::new());
|
||||||
|
|
||||||
let mut sub_app = App::empty();
|
let mut sub_app = App::empty();
|
||||||
sub_app.add_simple_outer_schedule();
|
sub_app.init_schedule(Main);
|
||||||
sub_app.init_schedule(CoreSchedule::Main);
|
|
||||||
app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app, update_rendering));
|
app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app, update_rendering));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{Extract, ExtractSchedule, RenderApp, RenderSet};
|
use crate::{Extract, ExtractSchedule, Render, RenderApp, RenderSet};
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
|
@ -80,7 +80,12 @@ impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app
|
render_app
|
||||||
|
.init_resource::<ExtractedAssets<A>>()
|
||||||
|
.init_resource::<RenderAssets<A>>()
|
||||||
|
.init_resource::<PrepareNextFrameAssets<A>>()
|
||||||
|
.add_systems(ExtractSchedule, extract_render_asset::<A>)
|
||||||
.configure_sets(
|
.configure_sets(
|
||||||
|
Render,
|
||||||
(
|
(
|
||||||
PrepareAssetSet::PreAssetPrepare,
|
PrepareAssetSet::PreAssetPrepare,
|
||||||
PrepareAssetSet::AssetPrepare,
|
PrepareAssetSet::AssetPrepare,
|
||||||
|
@ -89,13 +94,10 @@ impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
||||||
.chain()
|
.chain()
|
||||||
.in_set(RenderSet::Prepare),
|
.in_set(RenderSet::Prepare),
|
||||||
)
|
)
|
||||||
.init_resource::<ExtractedAssets<A>>()
|
.add_systems(
|
||||||
.init_resource::<RenderAssets<A>>()
|
Render,
|
||||||
.init_resource::<PrepareNextFrameAssets<A>>()
|
|
||||||
.add_systems((
|
|
||||||
extract_render_asset::<A>.in_schedule(ExtractSchedule),
|
|
||||||
prepare_assets::<A>.in_set(self.prepare_asset_set.clone()),
|
prepare_assets::<A>.in_set(self.prepare_asset_set.clone()),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ pub use texture_cache::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
render_asset::{PrepareAssetSet, RenderAssetPlugin},
|
render_asset::{PrepareAssetSet, RenderAssetPlugin},
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{AddAsset, Assets};
|
use bevy_asset::{AddAsset, Assets};
|
||||||
|
@ -115,7 +115,10 @@ impl Plugin for ImagePlugin {
|
||||||
.init_resource::<FallbackImageCubemap>()
|
.init_resource::<FallbackImageCubemap>()
|
||||||
.init_resource::<FallbackImageMsaaCache>()
|
.init_resource::<FallbackImageMsaaCache>()
|
||||||
.init_resource::<FallbackImageDepthCache>()
|
.init_resource::<FallbackImageDepthCache>()
|
||||||
.add_system(update_texture_cache_system.in_set(RenderSet::Cleanup));
|
.add_systems(
|
||||||
|
Render,
|
||||||
|
update_texture_cache_system.in_set(RenderSet::Cleanup),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
|
render_resource::{DynamicUniformBuffer, ShaderType, Texture, TextureView},
|
||||||
renderer::{RenderDevice, RenderQueue},
|
renderer::{RenderDevice, RenderQueue},
|
||||||
texture::{BevyDefault, TextureCache},
|
texture::{BevyDefault, TextureCache},
|
||||||
RenderApp, RenderSet,
|
Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
@ -55,14 +55,17 @@ impl Plugin for ViewPlugin {
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<ViewUniforms>()
|
.init_resource::<ViewUniforms>()
|
||||||
.configure_set(ViewSet::PrepareUniforms.in_set(RenderSet::Prepare))
|
.configure_set(Render, ViewSet::PrepareUniforms.in_set(RenderSet::Prepare))
|
||||||
.add_systems((
|
.add_systems(
|
||||||
prepare_view_uniforms.in_set(ViewSet::PrepareUniforms),
|
Render,
|
||||||
prepare_view_targets
|
(
|
||||||
.after(WindowSystem::Prepare)
|
prepare_view_uniforms.in_set(ViewSet::PrepareUniforms),
|
||||||
.in_set(RenderSet::Prepare)
|
prepare_view_targets
|
||||||
.after(crate::render_asset::prepare_assets::<Image>),
|
.after(WindowSystem::Prepare)
|
||||||
));
|
.in_set(RenderSet::Prepare)
|
||||||
|
.after(crate::render_asset::prepare_assets::<Image>),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ mod render_layers;
|
||||||
|
|
||||||
pub use render_layers::*;
|
pub use render_layers::*;
|
||||||
|
|
||||||
use bevy_app::{CoreSet, Plugin};
|
use bevy_app::{Plugin, PostUpdate};
|
||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_hierarchy::{Children, Parent};
|
use bevy_hierarchy::{Children, Parent};
|
||||||
|
@ -91,8 +91,8 @@ impl ComputedVisibility {
|
||||||
|
|
||||||
/// Whether this entity is visible to something this frame. This is true if and only if [`Self::is_visible_in_hierarchy`] and [`Self::is_visible_in_view`]
|
/// Whether this entity is visible to something this frame. This is true if and only if [`Self::is_visible_in_hierarchy`] and [`Self::is_visible_in_view`]
|
||||||
/// are true. This is the canonical method to call to determine if an entity should be drawn.
|
/// are true. This is the canonical method to call to determine if an entity should be drawn.
|
||||||
/// This value is updated in [`CoreSet::PostUpdate`] by the [`VisibilitySystems::CheckVisibility`] system set.
|
/// This value is updated in [`PostUpdate`] by the [`VisibilitySystems::CheckVisibility`] system set.
|
||||||
/// Reading it during [`CoreSet::Update`] will yield the value from the previous frame.
|
/// Reading it during [`Update`](bevy_app::Update) will yield the value from the previous frame.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_visible(&self) -> bool {
|
pub fn is_visible(&self) -> bool {
|
||||||
self.flags.bits == ComputedVisibilityFlags::all().bits
|
self.flags.bits == ComputedVisibilityFlags::all().bits
|
||||||
|
@ -100,7 +100,7 @@ impl ComputedVisibility {
|
||||||
|
|
||||||
/// Whether this entity is visible in the entity hierarchy, which is determined by the [`Visibility`] component.
|
/// Whether this entity is visible in the entity hierarchy, which is determined by the [`Visibility`] component.
|
||||||
/// This takes into account "visibility inheritance". If any of this entity's ancestors (see [`Parent`]) are hidden, this entity
|
/// This takes into account "visibility inheritance". If any of this entity's ancestors (see [`Parent`]) are hidden, this entity
|
||||||
/// will be hidden as well. This value is updated in the [`VisibilitySystems::VisibilityPropagate`], which lives under the [`CoreSet::PostUpdate`] set.
|
/// will be hidden as well. This value is updated in the [`VisibilitySystems::VisibilityPropagate`], which lives in the [`PostUpdate`] schedule.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_visible_in_hierarchy(&self) -> bool {
|
pub fn is_visible_in_hierarchy(&self) -> bool {
|
||||||
self.flags
|
self.flags
|
||||||
|
@ -110,8 +110,8 @@ impl ComputedVisibility {
|
||||||
/// Whether this entity is visible in _any_ view (Cameras, Lights, etc). Each entity type (and view type) should choose how to set this
|
/// Whether this entity is visible in _any_ view (Cameras, Lights, etc). Each entity type (and view type) should choose how to set this
|
||||||
/// value. For cameras and drawn entities, this will take into account [`RenderLayers`].
|
/// value. For cameras and drawn entities, this will take into account [`RenderLayers`].
|
||||||
///
|
///
|
||||||
/// This value is reset to `false` every frame in [`VisibilitySystems::VisibilityPropagate`] during [`CoreSet::PostUpdate`].
|
/// This value is reset to `false` every frame in [`VisibilitySystems::VisibilityPropagate`] during [`PostUpdate`].
|
||||||
/// Each entity type then chooses how to set this field in the [`VisibilitySystems::CheckVisibility`] system set, under [`CoreSet::PostUpdate`].
|
/// Each entity type then chooses how to set this field in the [`VisibilitySystems::CheckVisibility`] system set, in [`PostUpdate`].
|
||||||
/// Meshes might use frustum culling to decide if they are visible in a view.
|
/// Meshes might use frustum culling to decide if they are visible in a view.
|
||||||
/// Other entities might just set this to `true` every frame.
|
/// Other entities might just set this to `true` every frame.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -210,52 +210,49 @@ impl Plugin for VisibilityPlugin {
|
||||||
fn build(&self, app: &mut bevy_app::App) {
|
fn build(&self, app: &mut bevy_app::App) {
|
||||||
use VisibilitySystems::*;
|
use VisibilitySystems::*;
|
||||||
|
|
||||||
app.configure_set(CalculateBounds.in_base_set(CoreSet::PostUpdate))
|
app
|
||||||
// We add an AABB component in CalculateBounds, which must be ready on the same frame.
|
// We add an AABB component in CalculateBounds, which must be ready on the same frame.
|
||||||
.add_system(apply_system_buffers.in_set(CalculateBoundsFlush))
|
.add_systems(
|
||||||
.configure_set(
|
PostUpdate,
|
||||||
CalculateBoundsFlush
|
apply_system_buffers.in_set(CalculateBoundsFlush),
|
||||||
.after(CalculateBounds)
|
|
||||||
.in_base_set(CoreSet::PostUpdate),
|
|
||||||
)
|
)
|
||||||
.configure_set(UpdateOrthographicFrusta.in_base_set(CoreSet::PostUpdate))
|
.configure_set(PostUpdate, CalculateBoundsFlush.after(CalculateBounds))
|
||||||
.configure_set(UpdatePerspectiveFrusta.in_base_set(CoreSet::PostUpdate))
|
.add_systems(
|
||||||
.configure_set(UpdateProjectionFrusta.in_base_set(CoreSet::PostUpdate))
|
PostUpdate,
|
||||||
.configure_set(CheckVisibility.in_base_set(CoreSet::PostUpdate))
|
(
|
||||||
.configure_set(VisibilityPropagate.in_base_set(CoreSet::PostUpdate))
|
calculate_bounds.in_set(CalculateBounds),
|
||||||
.add_systems((
|
update_frusta::<OrthographicProjection>
|
||||||
calculate_bounds.in_set(CalculateBounds),
|
.in_set(UpdateOrthographicFrusta)
|
||||||
update_frusta::<OrthographicProjection>
|
.after(camera_system::<OrthographicProjection>)
|
||||||
.in_set(UpdateOrthographicFrusta)
|
.after(TransformSystem::TransformPropagate)
|
||||||
.after(camera_system::<OrthographicProjection>)
|
// We assume that no camera will have more than one projection component,
|
||||||
.after(TransformSystem::TransformPropagate)
|
// so these systems will run independently of one another.
|
||||||
// We assume that no camera will have more than one projection component,
|
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||||
// so these systems will run independently of one another.
|
.ambiguous_with(update_frusta::<PerspectiveProjection>)
|
||||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
.ambiguous_with(update_frusta::<Projection>),
|
||||||
.ambiguous_with(update_frusta::<PerspectiveProjection>)
|
update_frusta::<PerspectiveProjection>
|
||||||
.ambiguous_with(update_frusta::<Projection>),
|
.in_set(UpdatePerspectiveFrusta)
|
||||||
update_frusta::<PerspectiveProjection>
|
.after(camera_system::<PerspectiveProjection>)
|
||||||
.in_set(UpdatePerspectiveFrusta)
|
.after(TransformSystem::TransformPropagate)
|
||||||
.after(camera_system::<PerspectiveProjection>)
|
// We assume that no camera will have more than one projection component,
|
||||||
.after(TransformSystem::TransformPropagate)
|
// so these systems will run independently of one another.
|
||||||
// We assume that no camera will have more than one projection component,
|
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||||
// so these systems will run independently of one another.
|
.ambiguous_with(update_frusta::<Projection>),
|
||||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
update_frusta::<Projection>
|
||||||
.ambiguous_with(update_frusta::<Projection>),
|
.in_set(UpdateProjectionFrusta)
|
||||||
update_frusta::<Projection>
|
.after(camera_system::<Projection>)
|
||||||
.in_set(UpdateProjectionFrusta)
|
.after(TransformSystem::TransformPropagate),
|
||||||
.after(camera_system::<Projection>)
|
visibility_propagate_system.in_set(VisibilityPropagate),
|
||||||
.after(TransformSystem::TransformPropagate),
|
check_visibility
|
||||||
visibility_propagate_system.in_set(VisibilityPropagate),
|
.in_set(CheckVisibility)
|
||||||
check_visibility
|
.after(CalculateBoundsFlush)
|
||||||
.in_set(CheckVisibility)
|
.after(UpdateOrthographicFrusta)
|
||||||
.after(CalculateBoundsFlush)
|
.after(UpdatePerspectiveFrusta)
|
||||||
.after(UpdateOrthographicFrusta)
|
.after(UpdateProjectionFrusta)
|
||||||
.after(UpdatePerspectiveFrusta)
|
.after(VisibilityPropagate)
|
||||||
.after(UpdateProjectionFrusta)
|
.after(TransformSystem::TransformPropagate),
|
||||||
.after(VisibilityPropagate)
|
),
|
||||||
.after(TransformSystem::TransformPropagate),
|
);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,7 +454,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn visibility_propagation() {
|
fn visibility_propagation() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_system(visibility_propagate_system);
|
app.add_systems(Update, visibility_propagate_system);
|
||||||
|
|
||||||
let root1 = app
|
let root1 = app
|
||||||
.world
|
.world
|
||||||
|
@ -576,7 +573,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn visibility_propagation_unconditional_visible() {
|
fn visibility_propagation_unconditional_visible() {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
app.add_system(visibility_propagate_system);
|
app.add_systems(Update, visibility_propagate_system);
|
||||||
|
|
||||||
let root1 = app
|
let root1 = app
|
||||||
.world
|
.world
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
render_resource::TextureView,
|
render_resource::TextureView,
|
||||||
renderer::{RenderAdapter, RenderDevice, RenderInstance},
|
renderer::{RenderAdapter, RenderDevice, RenderInstance},
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_utils::{tracing::debug, HashMap, HashSet};
|
use bevy_utils::{tracing::debug, HashMap, HashSet};
|
||||||
use bevy_window::{
|
use bevy_window::{
|
||||||
|
@ -32,9 +32,9 @@ impl Plugin for WindowRenderPlugin {
|
||||||
.init_resource::<ExtractedWindows>()
|
.init_resource::<ExtractedWindows>()
|
||||||
.init_resource::<WindowSurfaces>()
|
.init_resource::<WindowSurfaces>()
|
||||||
.init_non_send_resource::<NonSendMarker>()
|
.init_non_send_resource::<NonSendMarker>()
|
||||||
.add_system(extract_windows.in_schedule(ExtractSchedule))
|
.add_systems(ExtractSchedule, extract_windows)
|
||||||
.configure_set(WindowSystem::Prepare.in_set(RenderSet::Prepare))
|
.configure_set(Render, WindowSystem::Prepare.in_set(RenderSet::Prepare))
|
||||||
.add_system(prepare_windows.in_set(WindowSystem::Prepare));
|
.add_systems(Render, prepare_windows.in_set(WindowSystem::Prepare));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ pub mod prelude {
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_asset::AddAsset;
|
use bevy_asset::AddAsset;
|
||||||
use bevy_ecs::prelude::*;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ScenePlugin;
|
pub struct ScenePlugin;
|
||||||
|
@ -36,9 +35,9 @@ impl Plugin for ScenePlugin {
|
||||||
.add_asset::<Scene>()
|
.add_asset::<Scene>()
|
||||||
.init_asset_loader::<SceneLoader>()
|
.init_asset_loader::<SceneLoader>()
|
||||||
.init_resource::<SceneSpawner>()
|
.init_resource::<SceneSpawner>()
|
||||||
.add_system(scene_spawner_system)
|
.add_systems(Update, scene_spawner_system)
|
||||||
// Systems `*_bundle_spawner` must run before `scene_spawner_system`
|
// Systems `*_bundle_spawner` must run before `scene_spawner_system`
|
||||||
.add_system(scene_spawner.in_base_set(CoreSet::PreUpdate));
|
.add_systems(PreUpdate, scene_spawner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ use bevy_reflect::TypeUuid;
|
||||||
use bevy_render::{
|
use bevy_render::{
|
||||||
render_phase::AddRenderCommand,
|
render_phase::AddRenderCommand,
|
||||||
render_resource::{Shader, SpecializedRenderPipelines},
|
render_resource::{Shader, SpecializedRenderPipelines},
|
||||||
ExtractSchedule, RenderApp, RenderSet,
|
ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -71,13 +71,14 @@ impl Plugin for SpritePlugin {
|
||||||
.init_resource::<SpriteAssetEvents>()
|
.init_resource::<SpriteAssetEvents>()
|
||||||
.add_render_command::<Transparent2d, DrawSprite>()
|
.add_render_command::<Transparent2d, DrawSprite>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
ExtractSchedule,
|
||||||
(
|
(
|
||||||
extract_sprites.in_set(SpriteSystem::ExtractSprites),
|
extract_sprites.in_set(SpriteSystem::ExtractSprites),
|
||||||
extract_sprite_events,
|
extract_sprite_events,
|
||||||
)
|
),
|
||||||
.in_schedule(ExtractSchedule),
|
|
||||||
)
|
)
|
||||||
.add_system(
|
.add_systems(
|
||||||
|
Render,
|
||||||
queue_sprites
|
queue_sprites
|
||||||
.in_set(RenderSet::Queue)
|
.in_set(RenderSet::Queue)
|
||||||
.ambiguous_with(queue_material2d_meshes::<ColorMaterial>),
|
.ambiguous_with(queue_material2d_meshes::<ColorMaterial>),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
use bevy_app::{App, Plugin};
|
||||||
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
||||||
use bevy_core_pipeline::{
|
use bevy_core_pipeline::{
|
||||||
core_2d::Transparent2d,
|
core_2d::Transparent2d,
|
||||||
|
@ -32,7 +32,7 @@ use bevy_render::{
|
||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
texture::FallbackImage,
|
texture::FallbackImage,
|
||||||
view::{ComputedVisibility, ExtractedView, Msaa, Visibility, VisibleEntities},
|
view::{ComputedVisibility, ExtractedView, Msaa, Visibility, VisibleEntities},
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::{GlobalTransform, Transform};
|
use bevy_transform::components::{GlobalTransform, Transform};
|
||||||
use bevy_utils::{FloatOrd, HashMap, HashSet};
|
use bevy_utils::{FloatOrd, HashMap, HashSet};
|
||||||
|
@ -161,13 +161,16 @@ where
|
||||||
.init_resource::<ExtractedMaterials2d<M>>()
|
.init_resource::<ExtractedMaterials2d<M>>()
|
||||||
.init_resource::<RenderMaterials2d<M>>()
|
.init_resource::<RenderMaterials2d<M>>()
|
||||||
.init_resource::<SpecializedMeshPipelines<Material2dPipeline<M>>>()
|
.init_resource::<SpecializedMeshPipelines<Material2dPipeline<M>>>()
|
||||||
.add_systems((
|
.add_systems(ExtractSchedule, extract_materials_2d::<M>)
|
||||||
extract_materials_2d::<M>.in_schedule(ExtractSchedule),
|
.add_systems(
|
||||||
prepare_materials_2d::<M>
|
Render,
|
||||||
.in_set(RenderSet::Prepare)
|
(
|
||||||
.after(PrepareAssetSet::PreAssetPrepare),
|
prepare_materials_2d::<M>
|
||||||
queue_material2d_meshes::<M>.in_set(RenderSet::Queue),
|
.in_set(RenderSet::Prepare)
|
||||||
));
|
.after(PrepareAssetSet::PreAssetPrepare),
|
||||||
|
queue_material2d_meshes::<M>.in_set(RenderSet::Queue),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy_app::{IntoSystemAppConfig, Plugin};
|
use bevy_app::Plugin;
|
||||||
use bevy_asset::{load_internal_asset, Handle, HandleUntyped};
|
use bevy_asset::{load_internal_asset, Handle, HandleUntyped};
|
||||||
|
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
|
@ -22,7 +22,7 @@ use bevy_render::{
|
||||||
view::{
|
view::{
|
||||||
ComputedVisibility, ExtractedView, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms,
|
ComputedVisibility, ExtractedView, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms,
|
||||||
},
|
},
|
||||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_transform::components::GlobalTransform;
|
use bevy_transform::components::GlobalTransform;
|
||||||
|
|
||||||
|
@ -103,11 +103,14 @@ impl Plugin for Mesh2dRenderPlugin {
|
||||||
render_app
|
render_app
|
||||||
.init_resource::<Mesh2dPipeline>()
|
.init_resource::<Mesh2dPipeline>()
|
||||||
.init_resource::<SpecializedMeshPipelines<Mesh2dPipeline>>()
|
.init_resource::<SpecializedMeshPipelines<Mesh2dPipeline>>()
|
||||||
.add_systems((
|
.add_systems(ExtractSchedule, extract_mesh2d)
|
||||||
extract_mesh2d.in_schedule(ExtractSchedule),
|
.add_systems(
|
||||||
queue_mesh2d_bind_group.in_set(RenderSet::Queue),
|
Render,
|
||||||
queue_mesh2d_view_bind_groups.in_set(RenderSet::Queue),
|
(
|
||||||
));
|
queue_mesh2d_bind_group.in_set(RenderSet::Queue),
|
||||||
|
queue_mesh2d_view_bind_groups.in_set(RenderSet::Queue),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,9 +79,9 @@ impl Plugin for TextPlugin {
|
||||||
.init_resource::<TextSettings>()
|
.init_resource::<TextSettings>()
|
||||||
.init_resource::<FontAtlasWarning>()
|
.init_resource::<FontAtlasWarning>()
|
||||||
.insert_resource(TextPipeline::default())
|
.insert_resource(TextPipeline::default())
|
||||||
.add_system(
|
.add_systems(
|
||||||
|
PostUpdate,
|
||||||
update_text2d_layout
|
update_text2d_layout
|
||||||
.in_base_set(CoreSet::PostUpdate)
|
|
||||||
// Potential conflict: `Assets<Image>`
|
// Potential conflict: `Assets<Image>`
|
||||||
// In practice, they run independently since `bevy_render::camera_update_system`
|
// In practice, they run independently since `bevy_render::camera_update_system`
|
||||||
// will only ever observe its own render target, and `update_text2d_layout`
|
// will only ever observe its own render target, and `update_text2d_layout`
|
||||||
|
@ -90,10 +90,9 @@ impl Plugin for TextPlugin {
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||||
render_app.add_system(
|
render_app.add_systems(
|
||||||
extract_text2d_sprite
|
ExtractSchedule,
|
||||||
.after(SpriteSystem::ExtractSprites)
|
extract_text2d_sprite.after(SpriteSystem::ExtractSprites),
|
||||||
.in_schedule(ExtractSchedule),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,14 @@ use bevy_utils::Duration;
|
||||||
/// If used for a fixed timestep system, use [`on_fixed_timer`] instead.
|
/// If used for a fixed timestep system, use [`on_fixed_timer`] instead.
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use bevy_app::{App, IntoSystemAppConfig, NoopPluginGroup as DefaultPlugins, PluginGroup};
|
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, Update};
|
||||||
/// # use bevy_ecs::schedule::IntoSystemConfig;
|
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||||
/// # use bevy_utils::Duration;
|
/// # use bevy_utils::Duration;
|
||||||
/// # use bevy_time::common_conditions::on_timer;
|
/// # use bevy_time::common_conditions::on_timer;
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .add_plugins(DefaultPlugins)
|
/// .add_plugins(DefaultPlugins)
|
||||||
/// .add_system(tick.run_if(on_timer(Duration::from_secs(1))))
|
/// .add_systems(Update, tick.run_if(on_timer(Duration::from_secs(1))))
|
||||||
/// .run();
|
/// .run();
|
||||||
/// }
|
/// }
|
||||||
/// fn tick() {
|
/// fn tick() {
|
||||||
|
@ -46,16 +46,15 @@ pub fn on_timer(duration: Duration) -> impl FnMut(Res<Time>) -> bool + Clone {
|
||||||
/// If used for a non-fixed timestep system, use [`on_timer`] instead.
|
/// If used for a non-fixed timestep system, use [`on_timer`] instead.
|
||||||
///
|
///
|
||||||
/// ```rust,no_run
|
/// ```rust,no_run
|
||||||
/// # use bevy_app::{App, CoreSchedule, IntoSystemAppConfig, NoopPluginGroup as DefaultPlugins, PluginGroup};
|
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, FixedUpdate};
|
||||||
/// # use bevy_ecs::schedule::IntoSystemConfig;
|
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||||
/// # use bevy_utils::Duration;
|
/// # use bevy_utils::Duration;
|
||||||
/// # use bevy_time::common_conditions::on_fixed_timer;
|
/// # use bevy_time::common_conditions::on_fixed_timer;
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// App::new()
|
/// App::new()
|
||||||
/// .add_plugins(DefaultPlugins)
|
/// .add_plugins(DefaultPlugins)
|
||||||
/// .add_system(
|
/// .add_systems(FixedUpdate,
|
||||||
/// tick.in_schedule(CoreSchedule::FixedUpdate)
|
/// tick.run_if(on_fixed_timer(Duration::from_secs(1))),
|
||||||
/// .run_if(on_fixed_timer(Duration::from_secs(1))),
|
|
||||||
/// )
|
/// )
|
||||||
/// .run();
|
/// .run();
|
||||||
/// }
|
/// }
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! Tools to run systems at a regular interval.
|
//! Tools to run systems at a regular interval.
|
||||||
//! This can be extremely useful for steady, frame-rate independent gameplay logic and physics.
|
//! This can be extremely useful for steady, frame-rate independent gameplay logic and physics.
|
||||||
//!
|
//!
|
||||||
//! To run a system on a fixed timestep, add it to the [`CoreSchedule::FixedUpdate`] [`Schedule`](bevy_ecs::schedule::Schedule).
|
//! To run a system on a fixed timestep, add it to the [`FixedUpdate`] [`Schedule`](bevy_ecs::schedule::Schedule).
|
||||||
//! This schedules is run in the [`CoreSet::FixedUpdate`](bevy_app::CoreSet::FixedUpdate) near the start of each frame,
|
//! This schedule is run in [`RunFixedUpdateLoop`](bevy_app::RunFixedUpdateLoop) near the start of each frame,
|
||||||
//! via the [`run_fixed_update_schedule`] exclusive system.
|
//! via the [`run_fixed_update_schedule`] exclusive system.
|
||||||
//!
|
//!
|
||||||
//! This schedule will be run a number of times each frame,
|
//! This schedule will be run a number of times each frame,
|
||||||
|
@ -22,7 +22,7 @@
|
||||||
//! variants for game simulation, but rather use the value of [`FixedTime`] instead.
|
//! variants for game simulation, but rather use the value of [`FixedTime`] instead.
|
||||||
|
|
||||||
use crate::Time;
|
use crate::Time;
|
||||||
use bevy_app::CoreSchedule;
|
use bevy_app::FixedUpdate;
|
||||||
use bevy_ecs::{system::Resource, world::World};
|
use bevy_ecs::{system::Resource, world::World};
|
||||||
use bevy_utils::Duration;
|
use bevy_utils::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -98,7 +98,7 @@ pub enum FixedUpdateError {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ticks the [`FixedTime`] resource then runs the [`CoreSchedule::FixedUpdate`].
|
/// Ticks the [`FixedTime`] resource then runs the [`FixedUpdate`].
|
||||||
pub fn run_fixed_update_schedule(world: &mut World) {
|
pub fn run_fixed_update_schedule(world: &mut World) {
|
||||||
// Tick the time
|
// Tick the time
|
||||||
let delta_time = world.resource::<Time>().delta();
|
let delta_time = world.resource::<Time>().delta();
|
||||||
|
@ -111,7 +111,7 @@ pub fn run_fixed_update_schedule(world: &mut World) {
|
||||||
let mut fixed_time = world.resource_mut::<FixedTime>();
|
let mut fixed_time = world.resource_mut::<FixedTime>();
|
||||||
let fixed_time_run = fixed_time.expend().is_ok();
|
let fixed_time_run = fixed_time.expend().is_ok();
|
||||||
if fixed_time_run {
|
if fixed_time_run {
|
||||||
world.run_schedule(CoreSchedule::FixedUpdate);
|
let _ = world.try_run_schedule(FixedUpdate);
|
||||||
} else {
|
} else {
|
||||||
check_again = false;
|
check_again = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ mod stopwatch;
|
||||||
mod time;
|
mod time;
|
||||||
mod timer;
|
mod timer;
|
||||||
|
|
||||||
use fixed_timestep::{run_fixed_update_schedule, FixedTime};
|
use fixed_timestep::FixedTime;
|
||||||
pub use stopwatch::*;
|
pub use stopwatch::*;
|
||||||
pub use time::*;
|
pub use time::*;
|
||||||
pub use timer::*;
|
pub use timer::*;
|
||||||
|
@ -21,9 +21,11 @@ pub mod prelude {
|
||||||
pub use crate::{fixed_timestep::FixedTime, Time, Timer, TimerMode};
|
pub use crate::{fixed_timestep::FixedTime, Time, Timer, TimerMode};
|
||||||
}
|
}
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::{prelude::*, RunFixedUpdateLoop};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
use crate::fixed_timestep::run_fixed_update_schedule;
|
||||||
|
|
||||||
/// Adds time functionality to Apps.
|
/// Adds time functionality to Apps.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TimePlugin;
|
pub struct TimePlugin;
|
||||||
|
@ -41,9 +43,8 @@ impl Plugin for TimePlugin {
|
||||||
.register_type::<Time>()
|
.register_type::<Time>()
|
||||||
.register_type::<Stopwatch>()
|
.register_type::<Stopwatch>()
|
||||||
.init_resource::<FixedTime>()
|
.init_resource::<FixedTime>()
|
||||||
.configure_set(TimeSystem.in_base_set(CoreSet::First))
|
.add_systems(First, time_system.in_set(TimeSystem))
|
||||||
.add_system(time_system.in_set(TimeSystem))
|
.add_systems(RunFixedUpdateLoop, run_fixed_update_schedule);
|
||||||
.add_system(run_fixed_update_schedule.in_base_set(CoreSet::FixedUpdate));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ impl Time {
|
||||||
/// world.insert_resource(Health { health_value: 0.2 });
|
/// world.insert_resource(Health { health_value: 0.2 });
|
||||||
///
|
///
|
||||||
/// let mut schedule = Schedule::new();
|
/// let mut schedule = Schedule::new();
|
||||||
/// schedule.add_system(health_system);
|
/// schedule.add_systems(health_system);
|
||||||
///
|
///
|
||||||
/// // Simulate that 30 ms have passed
|
/// // Simulate that 30 ms have passed
|
||||||
/// let mut time = world.resource_mut::<Time>();
|
/// let mut time = world.resource_mut::<Time>();
|
||||||
|
|
|
@ -24,7 +24,7 @@ use bevy_reflect::{std_traits::ReflectDefault, FromReflect, Reflect};
|
||||||
/// [`GlobalTransform`] is updated from [`Transform`] by systems in the system set
|
/// [`GlobalTransform`] is updated from [`Transform`] by systems in the system set
|
||||||
/// [`TransformPropagate`](crate::TransformSystem::TransformPropagate).
|
/// [`TransformPropagate`](crate::TransformSystem::TransformPropagate).
|
||||||
///
|
///
|
||||||
/// This system runs during [`CoreSet::PostUpdate`](crate::CoreSet::PostUpdate). If you
|
/// This system runs during [`PostUpdate`](bevy_app::PostUpdate). If you
|
||||||
/// update the [`Transform`] of an entity in this stage or after, you will notice a 1 frame lag
|
/// update the [`Transform`] of an entity in this stage or after, you will notice a 1 frame lag
|
||||||
/// before the [`GlobalTransform`] is updated.
|
/// before the [`GlobalTransform`] is updated.
|
||||||
///
|
///
|
||||||
|
|
|
@ -23,7 +23,7 @@ use std::ops::Mul;
|
||||||
/// [`GlobalTransform`] is updated from [`Transform`] by systems in the system set
|
/// [`GlobalTransform`] is updated from [`Transform`] by systems in the system set
|
||||||
/// [`TransformPropagate`](crate::TransformSystem::TransformPropagate).
|
/// [`TransformPropagate`](crate::TransformSystem::TransformPropagate).
|
||||||
///
|
///
|
||||||
/// This system runs during [`CoreSet::PostUpdate`](crate::CoreSet::PostUpdate). If you
|
/// This system runs during [`PostUpdate`](bevy_app::PostUpdate). If you
|
||||||
/// update the [`Transform`] of an entity during this set or after, you will notice a 1 frame lag
|
/// update the [`Transform`] of an entity during this set or after, you will notice a 1 frame lag
|
||||||
/// before the [`GlobalTransform`] is updated.
|
/// before the [`GlobalTransform`] is updated.
|
||||||
///
|
///
|
||||||
|
|
|
@ -40,7 +40,7 @@ use systems::{propagate_transforms, sync_simple_transforms};
|
||||||
/// [`GlobalTransform`] is updated from [`Transform`] by systems in the system set
|
/// [`GlobalTransform`] is updated from [`Transform`] by systems in the system set
|
||||||
/// [`TransformPropagate`](crate::TransformSystem::TransformPropagate).
|
/// [`TransformPropagate`](crate::TransformSystem::TransformPropagate).
|
||||||
///
|
///
|
||||||
/// This system runs during [`CoreSet::PostUpdate`](crate::CoreSet::PostUpdate). If you
|
/// This system runs during [`PostUpdate`](bevy_app::PostUpdate). If you
|
||||||
/// update the [`Transform`] of an entity in this stage or after, you will notice a 1 frame lag
|
/// update the [`Transform`] of an entity in this stage or after, you will notice a 1 frame lag
|
||||||
/// before the [`GlobalTransform`] is updated.
|
/// before the [`GlobalTransform`] is updated.
|
||||||
#[derive(Bundle, Clone, Copy, Debug, Default)]
|
#[derive(Bundle, Clone, Copy, Debug, Default)]
|
||||||
|
@ -61,7 +61,7 @@ impl TransformBundle {
|
||||||
/// Creates a new [`TransformBundle`] from a [`Transform`].
|
/// Creates a new [`TransformBundle`] from a [`Transform`].
|
||||||
///
|
///
|
||||||
/// This initializes [`GlobalTransform`] as identity, to be updated later by the
|
/// This initializes [`GlobalTransform`] as identity, to be updated later by the
|
||||||
/// [`CoreSet::PostUpdate`](crate::CoreSet::PostUpdate) stage.
|
/// [`PostUpdate`](bevy_app::PostUpdate) stage.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn from_transform(transform: Transform) -> Self {
|
pub const fn from_transform(transform: Transform) -> Self {
|
||||||
TransformBundle {
|
TransformBundle {
|
||||||
|
@ -98,28 +98,35 @@ impl Plugin for TransformPlugin {
|
||||||
app.register_type::<Transform>()
|
app.register_type::<Transform>()
|
||||||
.register_type::<GlobalTransform>()
|
.register_type::<GlobalTransform>()
|
||||||
.add_plugin(ValidParentCheckPlugin::<GlobalTransform>::default())
|
.add_plugin(ValidParentCheckPlugin::<GlobalTransform>::default())
|
||||||
|
.configure_set(
|
||||||
|
PostStartup,
|
||||||
|
PropagateTransformsSet.in_set(TransformSystem::TransformPropagate),
|
||||||
|
)
|
||||||
// add transform systems to startup so the first update is "correct"
|
// add transform systems to startup so the first update is "correct"
|
||||||
.configure_set(TransformSystem::TransformPropagate.in_base_set(CoreSet::PostUpdate))
|
.add_systems(
|
||||||
.configure_set(PropagateTransformsSet.in_set(TransformSystem::TransformPropagate))
|
PostStartup,
|
||||||
.edit_schedule(CoreSchedule::Startup, |schedule| {
|
(
|
||||||
schedule.configure_set(
|
sync_simple_transforms
|
||||||
TransformSystem::TransformPropagate.in_base_set(StartupSet::PostStartup),
|
.in_set(TransformSystem::TransformPropagate)
|
||||||
);
|
// FIXME: https://github.com/bevyengine/bevy/issues/4381
|
||||||
})
|
// These systems cannot access the same entities,
|
||||||
.add_startup_systems((
|
// due to subtle query filtering that is not yet correctly computed in the ambiguity detector
|
||||||
sync_simple_transforms
|
.ambiguous_with(PropagateTransformsSet),
|
||||||
.in_set(TransformSystem::TransformPropagate)
|
propagate_transforms.in_set(PropagateTransformsSet),
|
||||||
// FIXME: https://github.com/bevyengine/bevy/issues/4381
|
),
|
||||||
// These systems cannot access the same entities,
|
)
|
||||||
// due to subtle query filtering that is not yet correctly computed in the ambiguity detector
|
.configure_set(
|
||||||
.ambiguous_with(PropagateTransformsSet),
|
PostUpdate,
|
||||||
propagate_transforms.in_set(PropagateTransformsSet),
|
PropagateTransformsSet.in_set(TransformSystem::TransformPropagate),
|
||||||
))
|
)
|
||||||
.add_systems((
|
.add_systems(
|
||||||
sync_simple_transforms
|
PostUpdate,
|
||||||
.in_set(TransformSystem::TransformPropagate)
|
(
|
||||||
.ambiguous_with(PropagateTransformsSet),
|
sync_simple_transforms
|
||||||
propagate_transforms.in_set(PropagateTransformsSet),
|
.in_set(TransformSystem::TransformPropagate)
|
||||||
));
|
.ambiguous_with(PropagateTransformsSet),
|
||||||
|
propagate_transforms.in_set(PropagateTransformsSet),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -325,7 +325,7 @@ mod test {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
ComputeTaskPool::init(TaskPool::default);
|
ComputeTaskPool::init(TaskPool::default);
|
||||||
|
|
||||||
app.add_systems((sync_simple_transforms, propagate_transforms));
|
app.add_systems(Update, (sync_simple_transforms, propagate_transforms));
|
||||||
|
|
||||||
let translation = vec3(1.0, 0.0, 0.0);
|
let translation = vec3(1.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ mod test {
|
||||||
let mut temp = World::new();
|
let mut temp = World::new();
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
|
|
||||||
app.add_systems((propagate_transforms, sync_simple_transforms));
|
app.add_systems(Update, (propagate_transforms, sync_simple_transforms));
|
||||||
|
|
||||||
fn setup_world(world: &mut World) -> (Entity, Entity) {
|
fn setup_world(world: &mut World) -> (Entity, Entity) {
|
||||||
let mut grandchild = Entity::from_raw(0);
|
let mut grandchild = Entity::from_raw(0);
|
||||||
|
|
|
@ -1,25 +1,22 @@
|
||||||
|
use crate::{
|
||||||
|
prelude::{Button, Label},
|
||||||
|
Node, UiImage,
|
||||||
|
};
|
||||||
use bevy_a11y::{
|
use bevy_a11y::{
|
||||||
accesskit::{NodeBuilder, Rect, Role},
|
accesskit::{NodeBuilder, Rect, Role},
|
||||||
AccessibilityNode,
|
AccessibilityNode,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin, Update};
|
||||||
|
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::Entity,
|
prelude::Entity,
|
||||||
query::{Changed, Or, Without},
|
query::{Changed, Or, Without},
|
||||||
system::{Commands, Query},
|
system::{Commands, Query},
|
||||||
};
|
};
|
||||||
use bevy_hierarchy::Children;
|
use bevy_hierarchy::Children;
|
||||||
|
|
||||||
use bevy_render::prelude::Camera;
|
use bevy_render::prelude::Camera;
|
||||||
use bevy_text::Text;
|
use bevy_text::Text;
|
||||||
use bevy_transform::prelude::GlobalTransform;
|
use bevy_transform::prelude::GlobalTransform;
|
||||||
|
|
||||||
use crate::{
|
|
||||||
prelude::{Button, Label},
|
|
||||||
Node, UiImage,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn calc_name(texts: &Query<&Text>, children: &Children) -> Option<Box<str>> {
|
fn calc_name(texts: &Query<&Text>, children: &Children) -> Option<Box<str>> {
|
||||||
let mut name = None;
|
let mut name = None;
|
||||||
for child in children.iter() {
|
for child in children.iter() {
|
||||||
|
@ -149,6 +146,9 @@ pub(crate) struct AccessibilityPlugin;
|
||||||
|
|
||||||
impl Plugin for AccessibilityPlugin {
|
impl Plugin for AccessibilityPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems((calc_bounds, button_changed, image_changed, label_changed));
|
app.add_systems(
|
||||||
|
Update,
|
||||||
|
(calc_bounds, button_changed, image_changed, label_changed),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,15 +104,15 @@ impl Plugin for UiPlugin {
|
||||||
.register_type::<Val>()
|
.register_type::<Val>()
|
||||||
.register_type::<widget::Button>()
|
.register_type::<widget::Button>()
|
||||||
.register_type::<widget::Label>()
|
.register_type::<widget::Label>()
|
||||||
.configure_set(UiSystem::Focus.in_base_set(CoreSet::PreUpdate))
|
.add_systems(
|
||||||
.configure_set(UiSystem::Flex.in_base_set(CoreSet::PostUpdate))
|
PreUpdate,
|
||||||
.configure_set(UiSystem::Stack.in_base_set(CoreSet::PostUpdate))
|
ui_focus_system.in_set(UiSystem::Focus).after(InputSystem),
|
||||||
.add_system(ui_focus_system.in_set(UiSystem::Focus).after(InputSystem));
|
);
|
||||||
// add these systems to front because these must run before transform update systems
|
// add these systems to front because these must run before transform update systems
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
app.add_system(
|
app.add_systems(
|
||||||
|
PostUpdate,
|
||||||
widget::text_system
|
widget::text_system
|
||||||
.in_base_set(CoreSet::PostUpdate)
|
|
||||||
.before(UiSystem::Flex)
|
.before(UiSystem::Flex)
|
||||||
// Potential conflict: `Assets<Image>`
|
// Potential conflict: `Assets<Image>`
|
||||||
// In practice, they run independently since `bevy_render::camera_update_system`
|
// In practice, they run independently since `bevy_render::camera_update_system`
|
||||||
|
@ -126,10 +126,8 @@ impl Plugin for UiPlugin {
|
||||||
);
|
);
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
app.add_plugin(accessibility::AccessibilityPlugin);
|
app.add_plugin(accessibility::AccessibilityPlugin);
|
||||||
app.add_system({
|
app.add_systems(PostUpdate, {
|
||||||
let system = widget::update_image_calculated_size_system
|
let system = widget::update_image_calculated_size_system.before(UiSystem::Flex);
|
||||||
.in_base_set(CoreSet::PostUpdate)
|
|
||||||
.before(UiSystem::Flex);
|
|
||||||
// Potential conflicts: `Assets<Image>`
|
// Potential conflicts: `Assets<Image>`
|
||||||
// They run independently since `widget::image_node_system` will only ever observe
|
// They run independently since `widget::image_node_system` will only ever observe
|
||||||
// its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout`
|
// its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout`
|
||||||
|
@ -141,15 +139,16 @@ impl Plugin for UiPlugin {
|
||||||
|
|
||||||
system
|
system
|
||||||
})
|
})
|
||||||
.add_systems((
|
.add_systems(
|
||||||
flex_node_system
|
PostUpdate,
|
||||||
.in_set(UiSystem::Flex)
|
(
|
||||||
.before(TransformSystem::TransformPropagate),
|
flex_node_system
|
||||||
ui_stack_system.in_set(UiSystem::Stack),
|
.in_set(UiSystem::Flex)
|
||||||
update_clipping_system
|
.before(TransformSystem::TransformPropagate),
|
||||||
.after(TransformSystem::TransformPropagate)
|
ui_stack_system.in_set(UiSystem::Stack),
|
||||||
.in_base_set(CoreSet::PostUpdate),
|
update_clipping_system.after(TransformSystem::TransformPropagate),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
|
|
||||||
crate::render::build_ui_render(app);
|
crate::render::build_ui_render(app);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ mod pipeline;
|
||||||
mod render_pass;
|
mod render_pass;
|
||||||
|
|
||||||
use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d};
|
use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d};
|
||||||
use bevy_render::ExtractSchedule;
|
use bevy_render::{ExtractSchedule, Render};
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
use bevy_window::{PrimaryWindow, Window};
|
use bevy_window::{PrimaryWindow, Window};
|
||||||
pub use pipeline::*;
|
pub use pipeline::*;
|
||||||
|
@ -77,20 +77,23 @@ pub fn build_ui_render(app: &mut App) {
|
||||||
.init_resource::<DrawFunctions<TransparentUi>>()
|
.init_resource::<DrawFunctions<TransparentUi>>()
|
||||||
.add_render_command::<TransparentUi, DrawUi>()
|
.add_render_command::<TransparentUi, DrawUi>()
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
ExtractSchedule,
|
||||||
(
|
(
|
||||||
extract_default_ui_camera_view::<Camera2d>,
|
extract_default_ui_camera_view::<Camera2d>,
|
||||||
extract_default_ui_camera_view::<Camera3d>,
|
extract_default_ui_camera_view::<Camera3d>,
|
||||||
extract_uinodes.in_set(RenderUiSystem::ExtractNode),
|
extract_uinodes.in_set(RenderUiSystem::ExtractNode),
|
||||||
#[cfg(feature = "bevy_text")]
|
#[cfg(feature = "bevy_text")]
|
||||||
extract_text_uinodes.after(RenderUiSystem::ExtractNode),
|
extract_text_uinodes.after(RenderUiSystem::ExtractNode),
|
||||||
)
|
),
|
||||||
.in_schedule(ExtractSchedule),
|
|
||||||
)
|
)
|
||||||
.add_systems((
|
.add_systems(
|
||||||
prepare_uinodes.in_set(RenderSet::Prepare),
|
Render,
|
||||||
queue_uinodes.in_set(RenderSet::Queue),
|
(
|
||||||
sort_phase_system::<TransparentUi>.in_set(RenderSet::PhaseSort),
|
prepare_uinodes.in_set(RenderSet::Prepare),
|
||||||
));
|
queue_uinodes.in_set(RenderSet::Queue),
|
||||||
|
sort_phase_system::<TransparentUi>.in_set(RenderSet::PhaseSort),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Render graph
|
// Render graph
|
||||||
let ui_graph_2d = get_ui_graph(render_app);
|
let ui_graph_2d = get_ui_graph(render_app);
|
||||||
|
|
|
@ -196,7 +196,7 @@ mod tests {
|
||||||
queue.apply(&mut world);
|
queue.apply(&mut world);
|
||||||
|
|
||||||
let mut schedule = Schedule::default();
|
let mut schedule = Schedule::default();
|
||||||
schedule.add_system(ui_stack_system);
|
schedule.add_systems(ui_stack_system);
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
||||||
let mut query = world.query::<&Label>();
|
let mut query = world.query::<&Label>();
|
||||||
|
|
|
@ -22,7 +22,6 @@ pub mod prelude {
|
||||||
}
|
}
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_ecs::prelude::*;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
impl Default for WindowPlugin {
|
impl Default for WindowPlugin {
|
||||||
|
@ -53,14 +52,14 @@ pub struct WindowPlugin {
|
||||||
/// surprise your users. It is recommended to leave this setting to
|
/// surprise your users. It is recommended to leave this setting to
|
||||||
/// either [`ExitCondition::OnAllClosed`] or [`ExitCondition::OnPrimaryClosed`].
|
/// either [`ExitCondition::OnAllClosed`] or [`ExitCondition::OnPrimaryClosed`].
|
||||||
///
|
///
|
||||||
/// [`ExitCondition::OnAllClosed`] will add [`exit_on_all_closed`] to [`CoreSet::Update`].
|
/// [`ExitCondition::OnAllClosed`] will add [`exit_on_all_closed`] to [`Update`].
|
||||||
/// [`ExitCondition::OnPrimaryClosed`] will add [`exit_on_primary_closed`] to [`CoreSet::Update`].
|
/// [`ExitCondition::OnPrimaryClosed`] will add [`exit_on_primary_closed`] to [`Update`].
|
||||||
pub exit_condition: ExitCondition,
|
pub exit_condition: ExitCondition,
|
||||||
|
|
||||||
/// Whether to close windows when they are requested to be closed (i.e.
|
/// Whether to close windows when they are requested to be closed (i.e.
|
||||||
/// when the close button is pressed).
|
/// when the close button is pressed).
|
||||||
///
|
///
|
||||||
/// If true, this plugin will add [`close_when_requested`] to [`CoreSet::Update`].
|
/// If true, this plugin will add [`close_when_requested`] to [`Update`].
|
||||||
/// If this system (or a replacement) is not running, the close button will have no effect.
|
/// If this system (or a replacement) is not running, the close button will have no effect.
|
||||||
/// This may surprise your users. It is recommended to leave this setting as `true`.
|
/// This may surprise your users. It is recommended to leave this setting as `true`.
|
||||||
pub close_when_requested: bool,
|
pub close_when_requested: bool,
|
||||||
|
@ -93,17 +92,17 @@ impl Plugin for WindowPlugin {
|
||||||
|
|
||||||
match self.exit_condition {
|
match self.exit_condition {
|
||||||
ExitCondition::OnPrimaryClosed => {
|
ExitCondition::OnPrimaryClosed => {
|
||||||
app.add_system(exit_on_primary_closed.in_base_set(CoreSet::PostUpdate));
|
app.add_systems(PostUpdate, exit_on_primary_closed);
|
||||||
}
|
}
|
||||||
ExitCondition::OnAllClosed => {
|
ExitCondition::OnAllClosed => {
|
||||||
app.add_system(exit_on_all_closed.in_base_set(CoreSet::PostUpdate));
|
app.add_systems(PostUpdate, exit_on_all_closed);
|
||||||
}
|
}
|
||||||
ExitCondition::DontExit => {}
|
ExitCondition::DontExit => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.close_when_requested {
|
if self.close_when_requested {
|
||||||
// Need to run before `exit_on_*` systems
|
// Need to run before `exit_on_*` systems
|
||||||
app.add_system(close_when_requested);
|
app.add_systems(Update, close_when_requested);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register event types
|
// Register event types
|
||||||
|
@ -143,11 +142,11 @@ impl Plugin for WindowPlugin {
|
||||||
pub enum ExitCondition {
|
pub enum ExitCondition {
|
||||||
/// Close application when the primary window is closed
|
/// Close application when the primary window is closed
|
||||||
///
|
///
|
||||||
/// The plugin will add [`exit_on_primary_closed`] to [`CoreSet::Update`].
|
/// The plugin will add [`exit_on_primary_closed`] to [`Update`].
|
||||||
OnPrimaryClosed,
|
OnPrimaryClosed,
|
||||||
/// Close application when all windows are closed
|
/// Close application when all windows are closed
|
||||||
///
|
///
|
||||||
/// The plugin will add [`exit_on_all_closed`] to [`CoreSet::Update`].
|
/// The plugin will add [`exit_on_all_closed`] to [`Update`].
|
||||||
OnAllClosed,
|
OnAllClosed,
|
||||||
/// Keep application running headless even after closing all windows
|
/// Keep application running headless even after closing all windows
|
||||||
///
|
///
|
||||||
|
|
|
@ -8,7 +8,7 @@ use bevy_a11y::{
|
||||||
accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate},
|
accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate},
|
||||||
AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus,
|
AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus,
|
||||||
};
|
};
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin, Update};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
||||||
|
@ -163,11 +163,14 @@ impl Plugin for AccessibilityPlugin {
|
||||||
app.init_non_send_resource::<AccessKitAdapters>()
|
app.init_non_send_resource::<AccessKitAdapters>()
|
||||||
.init_resource::<WinitActionHandlers>()
|
.init_resource::<WinitActionHandlers>()
|
||||||
.add_event::<ActionRequest>()
|
.add_event::<ActionRequest>()
|
||||||
.add_systems((
|
.add_systems(
|
||||||
handle_window_focus,
|
Update,
|
||||||
window_closed,
|
(
|
||||||
poll_receivers,
|
handle_window_focus,
|
||||||
update_accessibility_nodes,
|
window_closed,
|
||||||
));
|
poll_receivers,
|
||||||
|
update_accessibility_nodes,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use system::{changed_window, create_window, despawn_window, CachedWindow};
|
||||||
pub use winit_config::*;
|
pub use winit_config::*;
|
||||||
pub use winit_windows::*;
|
pub use winit_windows::*;
|
||||||
|
|
||||||
use bevy_app::{App, AppExit, CoreSet, Plugin};
|
use bevy_app::{App, AppExit, Last, Plugin};
|
||||||
use bevy_ecs::event::{Events, ManualEventReader};
|
use bevy_ecs::event::{Events, ManualEventReader};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_input::{
|
use bevy_input::{
|
||||||
|
@ -76,12 +76,12 @@ impl Plugin for WinitPlugin {
|
||||||
// exit_on_all_closed only uses the query to determine if the query is empty,
|
// exit_on_all_closed only uses the query to determine if the query is empty,
|
||||||
// and so doesn't care about ordering relative to changed_window
|
// and so doesn't care about ordering relative to changed_window
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
Last,
|
||||||
(
|
(
|
||||||
changed_window.ambiguous_with(exit_on_all_closed),
|
changed_window.ambiguous_with(exit_on_all_closed),
|
||||||
// Update the state of the window before attempting to despawn to ensure consistent event ordering
|
// Update the state of the window before attempting to despawn to ensure consistent event ordering
|
||||||
despawn_window.after(changed_window),
|
despawn_window.after(changed_window),
|
||||||
)
|
),
|
||||||
.in_base_set(CoreSet::Last),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
app.add_plugin(AccessibilityPlugin);
|
app.add_plugin(AccessibilityPlugin);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::WinitWindows;
|
use crate::WinitWindows;
|
||||||
use bevy_app::{App, Plugin};
|
use bevy_app::{App, Plugin, Update};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
|
@ -10,7 +10,7 @@ pub(crate) struct CanvasParentResizePlugin;
|
||||||
impl Plugin for CanvasParentResizePlugin {
|
impl Plugin for CanvasParentResizePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<CanvasParentResizeEventChannel>()
|
app.init_resource::<CanvasParentResizeEventChannel>()
|
||||||
.add_system(canvas_parent_resize_event_handler);
|
.add_systems(Update, canvas_parent_resize_event_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ fn move_enemies_to_player(
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_system(move_enemies_to_player)
|
.add_systems(Update, move_enemies_to_player)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -55,7 +55,7 @@ fn move_enemies_to_player(
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_system(move_enemies_to_player)
|
.add_systems(Update, move_enemies_to_player)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -85,7 +85,7 @@ fn move_enemies_to_player(
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_system(move_enemies_to_player)
|
.add_systems(Update, move_enemies_to_player)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -17,7 +17,7 @@ fn update_materials(
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_system(update_materials)
|
.add_systems(Update, update_materials)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -38,7 +38,7 @@ fn update_materials(
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_system(update_materials)
|
.add_systems(Update, update_materials)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -10,9 +10,9 @@ use bevy::prelude::*;
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_startup_system(setup)
|
.add_systems(Startup, setup)
|
||||||
.add_system(despawning)
|
.add_systems(Update, despawning)
|
||||||
.add_system(use_entity.after(despawning))
|
.add_systems(Update, use_entity.after(despawning))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ fn setup_cube(
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_startup_system(setup_cube)
|
.add_systems(Startup, setup_cube)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -97,7 +97,7 @@ fn setup_cube(
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_startup_system(setup_cube)
|
.add_systems(Startup, setup_cube)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -5,7 +5,7 @@ use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_startup_system(setup)
|
.add_systems(Startup, setup)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.insert_resource(ClearColor(Color::DARK_GRAY))
|
.insert_resource(ClearColor(Color::DARK_GRAY))
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_systems((setup.on_startup(), update_bloom_settings))
|
.add_systems(Startup, setup)
|
||||||
|
.add_systems(Update, update_bloom_settings)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_startup_system(setup)
|
.add_systems(Startup, setup)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue