mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +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() {}
|
||||
let mut schedule = Schedule::new();
|
||||
for _ in 0..system_count {
|
||||
schedule.add_system(empty);
|
||||
schedule.add_systems(empty);
|
||||
}
|
||||
schedule.run(&mut world);
|
||||
(world, schedule)
|
||||
|
|
|
@ -154,7 +154,7 @@ fn empty_archetypes(criterion: &mut Criterion) {
|
|||
let mut group = criterion.benchmark_group("empty_archetypes");
|
||||
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
||||
let (mut world, mut schedule) = setup(true, |schedule| {
|
||||
schedule.add_system(iter);
|
||||
schedule.add_systems(iter);
|
||||
});
|
||||
add_archetypes(&mut world, archetype_count);
|
||||
world.clear_entities();
|
||||
|
@ -185,7 +185,7 @@ fn empty_archetypes(criterion: &mut Criterion) {
|
|||
}
|
||||
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
||||
let (mut world, mut schedule) = setup(true, |schedule| {
|
||||
schedule.add_system(for_each);
|
||||
schedule.add_systems(for_each);
|
||||
});
|
||||
add_archetypes(&mut world, archetype_count);
|
||||
world.clear_entities();
|
||||
|
@ -216,7 +216,7 @@ fn empty_archetypes(criterion: &mut Criterion) {
|
|||
}
|
||||
for archetype_count in [10, 100, 500, 1000, 2000, 5000, 10000] {
|
||||
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);
|
||||
world.clear_entities();
|
||||
|
|
|
@ -19,7 +19,7 @@ pub fn run_condition_yes(criterion: &mut Criterion) {
|
|||
fn empty() {}
|
||||
for amount in 0..21 {
|
||||
let mut schedule = Schedule::new();
|
||||
schedule.add_system(empty.run_if(yes));
|
||||
schedule.add_systems(empty.run_if(yes));
|
||||
for _ in 0..amount {
|
||||
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() {}
|
||||
for amount in 0..21 {
|
||||
let mut schedule = Schedule::new();
|
||||
schedule.add_system(empty.run_if(no));
|
||||
schedule.add_systems(empty.run_if(no));
|
||||
for _ in 0..amount {
|
||||
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 {
|
||||
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 {
|
||||
schedule.add_systems(
|
||||
(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 {
|
||||
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 {
|
||||
schedule.add_systems(
|
||||
(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 {
|
||||
let mut schedule = Schedule::new();
|
||||
for _ in 0..amount {
|
||||
schedule.add_system(empty);
|
||||
schedule.add_systems(empty);
|
||||
}
|
||||
schedule.run(&mut world);
|
||||
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 criterion::Criterion;
|
||||
|
||||
|
@ -72,7 +72,7 @@ pub fn build_schedule(criterion: &mut Criterion) {
|
|||
group.measurement_time(std::time::Duration::from_secs(15));
|
||||
|
||||
// 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.
|
||||
let labels: Vec<_> = (0..1000).map(|i| NumSet(i)).collect();
|
||||
|
||||
|
@ -83,7 +83,7 @@ pub fn build_schedule(criterion: &mut Criterion) {
|
|||
bencher.iter(|| {
|
||||
let mut app = App::new();
|
||||
for _ in 0..graph_size {
|
||||
app.add_system(empty_system);
|
||||
app.add_systems(Update, empty_system);
|
||||
}
|
||||
app.update();
|
||||
});
|
||||
|
@ -93,7 +93,7 @@ pub fn build_schedule(criterion: &mut Criterion) {
|
|||
group.bench_function(format!("{graph_size}_schedule"), |bencher| {
|
||||
bencher.iter(|| {
|
||||
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.
|
||||
// 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] {
|
||||
sys = sys.before(*label);
|
||||
}
|
||||
app.add_system(sys);
|
||||
app.add_systems(Update, sys);
|
||||
}
|
||||
// Run the app for a single frame.
|
||||
// This is necessary since dependency resolution does not occur until the game runs.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use std::ops::Deref;
|
||||
use std::time::Duration;
|
||||
|
||||
use bevy_app::{App, CoreSet, Plugin};
|
||||
use bevy_app::{App, Plugin, PostUpdate};
|
||||
use bevy_asset::{AddAsset, Assets, Handle};
|
||||
use bevy_core::Name;
|
||||
use bevy_ecs::prelude::*;
|
||||
|
@ -550,10 +550,9 @@ impl Plugin for AnimationPlugin {
|
|||
app.add_asset::<AnimationClip>()
|
||||
.register_asset_reflect::<AnimationClip>()
|
||||
.register_type::<AnimationPlayer>()
|
||||
.add_system(
|
||||
animation_player
|
||||
.in_base_set(CoreSet::PostUpdate)
|
||||
.before(TransformSystem::TransformPropagate),
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
animation_player.before(TransformSystem::TransformPropagate),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
use crate::{
|
||||
CoreSchedule, CoreSet, IntoSystemAppConfig, IntoSystemAppConfigs, Plugin, PluginGroup,
|
||||
StartupSet, SystemAppConfig,
|
||||
First, Main, MainSchedulePlugin, Plugin, PluginGroup, Startup, StateTransition, Update,
|
||||
};
|
||||
pub use bevy_derive::AppLabel;
|
||||
use bevy_ecs::{
|
||||
prelude::*,
|
||||
schedule::{
|
||||
apply_state_transition, common_conditions::run_once as run_once_condition,
|
||||
run_enter_schedule, BoxedScheduleLabel, IntoSystemConfig, IntoSystemSetConfigs,
|
||||
run_enter_schedule, BoxedScheduleLabel, IntoSystemConfigs, IntoSystemSetConfigs,
|
||||
ScheduleLabel,
|
||||
},
|
||||
};
|
||||
|
@ -53,7 +52,7 @@ pub(crate) enum AppError {
|
|||
/// #
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_system(hello_world_system)
|
||||
/// .add_systems(Update, hello_world_system)
|
||||
/// .run();
|
||||
/// }
|
||||
///
|
||||
|
@ -74,12 +73,10 @@ pub struct App {
|
|||
pub runner: Box<dyn Fn(App) + Send>, // Send bound is required to make App Send
|
||||
/// The schedule that systems are added to by default.
|
||||
///
|
||||
/// This is initially set to [`CoreSchedule::Main`].
|
||||
pub default_schedule_label: BoxedScheduleLabel,
|
||||
/// The schedule that controls the outer loop of schedule execution.
|
||||
/// The schedule that runs the main loop of schedule execution.
|
||||
///
|
||||
/// This is initially set to [`CoreSchedule::Outer`].
|
||||
pub outer_schedule_label: BoxedScheduleLabel,
|
||||
/// This is initially set to [`Main`].
|
||||
pub main_schedule_label: BoxedScheduleLabel,
|
||||
sub_apps: HashMap<AppLabelId, SubApp>,
|
||||
plugin_registry: Vec<Box<dyn Plugin>>,
|
||||
plugin_name_added: HashSet<String>,
|
||||
|
@ -104,7 +101,7 @@ impl Debug for App {
|
|||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use bevy_app::{App, AppLabel, SubApp, CoreSchedule};
|
||||
/// # use bevy_app::{App, AppLabel, SubApp, Main};
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_ecs::schedule::ScheduleLabel;
|
||||
///
|
||||
|
@ -122,12 +119,10 @@ impl Debug for App {
|
|||
/// // create a app with a resource and a single schedule
|
||||
/// let mut sub_app = App::empty();
|
||||
/// // add an outer schedule that runs the main schedule
|
||||
/// sub_app.add_simple_outer_schedule();
|
||||
/// sub_app.insert_resource(Val(100));
|
||||
///
|
||||
/// // initialize main schedule
|
||||
/// sub_app.init_schedule(CoreSchedule::Main);
|
||||
/// sub_app.add_system(|counter: Res<Val>| {
|
||||
/// sub_app.add_systems(Main, |counter: Res<Val>| {
|
||||
/// // since we assigned the value from the main world in extract
|
||||
/// // we see that value instead of 100
|
||||
/// assert_eq!(counter.0, 10);
|
||||
|
@ -169,7 +164,7 @@ impl SubApp {
|
|||
pub fn run(&mut self) {
|
||||
self.app
|
||||
.world
|
||||
.run_schedule_ref(&*self.app.outer_schedule_label);
|
||||
.run_schedule_ref(&*self.app.main_schedule_label);
|
||||
self.app.world.clear_trackers();
|
||||
}
|
||||
|
||||
|
@ -195,8 +190,7 @@ impl Default for App {
|
|||
#[cfg(feature = "bevy_reflect")]
|
||||
app.init_resource::<AppTypeRegistry>();
|
||||
|
||||
app.add_default_schedules();
|
||||
|
||||
app.add_plugin(MainSchedulePlugin);
|
||||
app.add_event::<AppExit>();
|
||||
|
||||
#[cfg(feature = "bevy_ci_testing")]
|
||||
|
@ -211,8 +205,6 @@ impl Default for App {
|
|||
impl App {
|
||||
/// Creates a new [`App`] with some default structure to enable core engine features.
|
||||
/// This is the preferred constructor for most use cases.
|
||||
///
|
||||
/// This calls [`App::add_default_schedules`].
|
||||
pub fn new() -> App {
|
||||
App::default()
|
||||
}
|
||||
|
@ -229,8 +221,7 @@ impl App {
|
|||
sub_apps: HashMap::default(),
|
||||
plugin_registry: Vec::default(),
|
||||
plugin_name_added: Default::default(),
|
||||
default_schedule_label: Box::new(CoreSchedule::Main),
|
||||
outer_schedule_label: Box::new(CoreSchedule::Outer),
|
||||
main_schedule_label: Box::new(Main),
|
||||
building_plugin_depth: 0,
|
||||
}
|
||||
}
|
||||
|
@ -240,9 +231,8 @@ impl App {
|
|||
/// This method also updates sub apps.
|
||||
/// 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.
|
||||
/// In normal usage, this is [`CoreSchedule::Outer`], which will run [`CoreSchedule::Startup`]
|
||||
/// the first time the app is run, then [`CoreSchedule::Main`] on every call of this method.
|
||||
/// The schedule run by this method is determined by the [`main_schedule_label`](App) field.
|
||||
/// By default this is [`Main`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
|
@ -251,7 +241,7 @@ impl App {
|
|||
{
|
||||
#[cfg(feature = "trace")]
|
||||
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() {
|
||||
#[cfg(feature = "trace")]
|
||||
|
@ -317,13 +307,13 @@ impl App {
|
|||
|
||||
/// 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
|
||||
/// [`CoreSet::StateTransitions`] so that transitions happen before [`CoreSet::Update`] and
|
||||
/// a instance of [`run_enter_schedule::<S>`] in [`CoreSet::StateTransitions`] with a
|
||||
/// [`StateTransition`] so that transitions happen before [`Update`] and
|
||||
/// 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
|
||||
/// initial state.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// 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
|
||||
/// by adding the [`apply_state_transition`] system manually.
|
||||
pub fn add_state<S: States>(&mut self) -> &mut Self {
|
||||
self.init_resource::<State<S>>();
|
||||
self.init_resource::<NextState<S>>();
|
||||
|
||||
let mut schedules = self.world.resource_mut::<Schedules>();
|
||||
|
||||
let Some(default_schedule) = schedules.get_mut(&*self.default_schedule_label) else {
|
||||
let schedule_label = &self.default_schedule_label;
|
||||
panic!("Default schedule {schedule_label:?} does not exist.")
|
||||
};
|
||||
|
||||
default_schedule.add_systems(
|
||||
(
|
||||
run_enter_schedule::<S>.run_if(run_once_condition()),
|
||||
apply_state_transition::<S>,
|
||||
)
|
||||
.chain()
|
||||
.in_base_set(CoreSet::StateTransitions),
|
||||
);
|
||||
self.init_resource::<State<S>>()
|
||||
.init_resource::<NextState<S>>()
|
||||
.add_systems(
|
||||
StateTransition,
|
||||
(
|
||||
run_enter_schedule::<S>.run_if(run_once_condition()),
|
||||
apply_state_transition::<S>,
|
||||
)
|
||||
.chain(),
|
||||
);
|
||||
|
||||
for variant in S::variants() {
|
||||
default_schedule.configure_set(
|
||||
OnUpdate(variant.clone())
|
||||
.in_base_set(CoreSet::Update)
|
||||
.run_if(in_state(variant)),
|
||||
);
|
||||
self.configure_set(Update, OnUpdate(variant.clone()).run_if(in_state(variant)));
|
||||
}
|
||||
|
||||
// The OnEnter, OnExit, and OnTransition schedules are lazily initialized
|
||||
|
@ -382,30 +360,15 @@ impl App {
|
|||
/// #
|
||||
/// app.add_system(my_system);
|
||||
/// ```
|
||||
pub fn add_system<M>(&mut self, system: impl IntoSystemAppConfig<M>) -> &mut Self {
|
||||
let mut schedules = self.world.resource_mut::<Schedules>();
|
||||
|
||||
let SystemAppConfig { system, schedule } = system.into_app_config();
|
||||
|
||||
if let Some(schedule_label) = schedule {
|
||||
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
|
||||
#[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(Update, your_system).`"
|
||||
)]
|
||||
pub fn add_system<M>(&mut self, system: impl IntoSystemConfigs<M>) -> &mut Self {
|
||||
self.add_systems(Update, system)
|
||||
}
|
||||
|
||||
/// 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
|
||||
///
|
||||
|
@ -418,36 +381,27 @@ impl App {
|
|||
/// # fn system_b() {}
|
||||
/// # 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>();
|
||||
|
||||
match systems.into_app_configs().0 {
|
||||
crate::InnerConfigs::Blanket { systems, schedule } => {
|
||||
let schedule = if let Some(label) = schedule {
|
||||
schedules
|
||||
.get_mut(&*label)
|
||||
.unwrap_or_else(|| panic!("Schedule '{label:?}' does not exist."))
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
if let Some(schedule) = schedules.get_mut(&schedule) {
|
||||
schedule.add_systems(systems);
|
||||
} else {
|
||||
let mut new_schedule = Schedule::new();
|
||||
new_schedule.add_systems(systems);
|
||||
schedules.insert(schedule, new_schedule);
|
||||
}
|
||||
|
||||
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.
|
||||
/// To add a system that runs every frame, see [`add_system`](Self::add_system).
|
||||
|
@ -463,13 +417,17 @@ impl App {
|
|||
/// }
|
||||
///
|
||||
/// 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 {
|
||||
self.add_system(system.in_schedule(CoreSchedule::Startup))
|
||||
#[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_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
|
||||
///
|
||||
|
@ -482,88 +440,58 @@ impl App {
|
|||
/// # fn startup_system_b() {}
|
||||
/// # fn startup_system_c() {}
|
||||
/// #
|
||||
/// app.add_startup_systems((
|
||||
/// app.add_systems(Startup, (
|
||||
/// startup_system_a,
|
||||
/// startup_system_b,
|
||||
/// 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 {
|
||||
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.
|
||||
pub fn configure_set(&mut self, set: impl IntoSystemSetConfig) -> &mut Self {
|
||||
self.world
|
||||
.resource_mut::<Schedules>()
|
||||
.get_mut(&*self.default_schedule_label)
|
||||
.unwrap()
|
||||
.configure_set(set);
|
||||
pub fn configure_set(
|
||||
&mut self,
|
||||
schedule: impl ScheduleLabel,
|
||||
set: impl IntoSystemSetConfig,
|
||||
) -> &mut Self {
|
||||
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
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
self.world
|
||||
.resource_mut::<Schedules>()
|
||||
.get_mut(&*self.default_schedule_label)
|
||||
.unwrap()
|
||||
.configure_sets(sets);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds standardized schedules and labels to an [`App`].
|
||||
///
|
||||
/// Adding these schedules is necessary to make almost all core engine features work.
|
||||
/// 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);
|
||||
pub fn configure_sets(
|
||||
&mut self,
|
||||
schedule: impl ScheduleLabel,
|
||||
sets: impl IntoSystemSetConfigs,
|
||||
) -> &mut Self {
|
||||
let mut schedules = self.world.resource_mut::<Schedules>();
|
||||
if let Some(schedule) = schedules.get_mut(&schedule) {
|
||||
schedule.configure_sets(sets);
|
||||
} else {
|
||||
let mut new_schedule = Schedule::new();
|
||||
new_schedule.configure_sets(sets);
|
||||
schedules.insert(schedule, new_schedule);
|
||||
}
|
||||
|
||||
self.edit_schedule(CoreSchedule::Outer, |schedule| {
|
||||
schedule.set_executor_kind(bevy_ecs::schedule::ExecutorKind::SingleThreaded);
|
||||
schedule.add_system(run_main_schedule);
|
||||
});
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// Setup the application to manage events of type `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.
|
||||
///
|
||||
|
@ -584,7 +512,7 @@ impl App {
|
|||
{
|
||||
if !self.world.contains_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
|
||||
}
|
||||
|
@ -1025,7 +953,7 @@ mod tests {
|
|||
system::Commands,
|
||||
};
|
||||
|
||||
use crate::{App, IntoSystemAppConfig, IntoSystemAppConfigs, Plugin};
|
||||
use crate::{App, Plugin};
|
||||
|
||||
struct PluginA;
|
||||
impl Plugin for PluginA {
|
||||
|
@ -1097,31 +1025,11 @@ mod tests {
|
|||
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]
|
||||
fn add_systems_should_create_schedule_if_it_does_not_exist() {
|
||||
let mut app = App::new();
|
||||
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));
|
||||
assert_eq!(app.world.entities().len(), 2);
|
||||
|
@ -1130,7 +1038,7 @@ mod tests {
|
|||
#[test]
|
||||
fn add_systems_should_create_schedule_if_it_does_not_exist2() {
|
||||
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>();
|
||||
|
||||
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 bevy_ecs::prelude::Resource;
|
||||
|
@ -47,7 +47,7 @@ pub(crate) fn setup_app(app: &mut App) -> &mut App {
|
|||
};
|
||||
|
||||
app.insert_resource(config)
|
||||
.add_system(ci_testing_exit_after);
|
||||
.add_systems(Update, ci_testing_exit_after);
|
||||
|
||||
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)]
|
||||
|
||||
mod app;
|
||||
mod config;
|
||||
mod main_schedule;
|
||||
mod plugin;
|
||||
mod plugin_group;
|
||||
mod schedule_runner;
|
||||
|
@ -13,7 +13,7 @@ mod ci_testing;
|
|||
|
||||
pub use app::*;
|
||||
pub use bevy_derive::DynamicPlugin;
|
||||
pub use config::*;
|
||||
pub use main_schedule::*;
|
||||
pub use plugin::*;
|
||||
pub use plugin_group::*;
|
||||
pub use schedule_runner::*;
|
||||
|
@ -26,197 +26,10 @@ pub mod prelude {
|
|||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
app::App,
|
||||
config::{IntoSystemAppConfig, IntoSystemAppConfigs},
|
||||
CoreSchedule, CoreSet, DynamicPlugin, Plugin, PluginGroup, StartupSet,
|
||||
main_schedule::{
|
||||
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 {
|
||||
use super::*;
|
||||
use crate::{loader::LoadedAsset, update_asset_storage_system};
|
||||
use bevy_app::App;
|
||||
use bevy_app::{App, Update};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_utils::BoxedFuture;
|
||||
|
@ -852,10 +852,13 @@ mod test {
|
|||
let mut app = App::new();
|
||||
app.insert_resource(assets);
|
||||
app.insert_resource(asset_server);
|
||||
app.add_systems((
|
||||
free_unused_assets_system.in_set(FreeUnusedAssets),
|
||||
update_asset_storage_system::<PngAsset>.after(FreeUnusedAssets),
|
||||
));
|
||||
app.add_systems(
|
||||
Update,
|
||||
(
|
||||
free_unused_assets_system.in_set(FreeUnusedAssets),
|
||||
update_asset_storage_system::<PngAsset>.after(FreeUnusedAssets),
|
||||
),
|
||||
);
|
||||
|
||||
fn load_asset(path: AssetPath, world: &World) -> HandleUntyped {
|
||||
let asset_server = world.resource::<AssetServer>();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
update_asset_storage_system, Asset, AssetLoader, AssetServer, AssetSet, Handle, HandleId,
|
||||
RefChange, ReflectAsset, ReflectHandle,
|
||||
update_asset_storage_system, Asset, AssetEvents, AssetLoader, AssetServer, Handle, HandleId,
|
||||
LoadAssets, RefChange, ReflectAsset, ReflectHandle,
|
||||
};
|
||||
use bevy_app::{App, AppTypeRegistry};
|
||||
use bevy_ecs::prelude::*;
|
||||
|
@ -331,10 +331,8 @@ impl AddAsset for App {
|
|||
};
|
||||
|
||||
self.insert_resource(assets)
|
||||
.add_systems((
|
||||
Assets::<T>::asset_event_system.in_base_set(AssetSet::AssetEvents),
|
||||
update_asset_storage_system::<T>.in_base_set(AssetSet::LoadAssets),
|
||||
))
|
||||
.add_systems(LoadAssets, update_asset_storage_system::<T>)
|
||||
.add_systems(AssetEvents, Assets::<T>::asset_event_system)
|
||||
.register_type::<Handle<T>>()
|
||||
.add_event::<AssetEvent<T>>()
|
||||
}
|
||||
|
@ -362,9 +360,9 @@ impl AddAsset for App {
|
|||
{
|
||||
#[cfg(feature = "debug_asset_server")]
|
||||
{
|
||||
self.add_system(
|
||||
crate::debug_asset_server::sync_debug_assets::<T>
|
||||
.in_base_set(bevy_app::CoreSet::Update),
|
||||
self.add_systems(
|
||||
bevy_app::Update,
|
||||
crate::debug_asset_server::sync_debug_assets::<T>,
|
||||
);
|
||||
let mut app = self
|
||||
.world
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
//!
|
||||
//! Internal assets (e.g. shaders) are bundled directly into an application and can't be hot
|
||||
//! reloaded using the conventional API.
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_app::{App, Plugin, Update};
|
||||
use bevy_ecs::{prelude::*, system::SystemState};
|
||||
use bevy_tasks::{IoTaskPool, TaskPoolBuilder};
|
||||
use bevy_utils::HashMap;
|
||||
|
@ -75,7 +75,7 @@ impl Plugin for DebugAssetServerPlugin {
|
|||
watch_for_changes: true,
|
||||
});
|
||||
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> {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_startup_system(Self::setup_system)
|
||||
.add_system(Self::diagnostic_system);
|
||||
app.add_systems(Startup, Self::setup_system)
|
||||
.add_systems(Update, Self::diagnostic_system);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,18 +46,15 @@ pub use loader::*;
|
|||
pub use path::*;
|
||||
pub use reflect::*;
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_app::{prelude::*, MainScheduleOrder};
|
||||
use bevy_ecs::schedule::ScheduleLabel;
|
||||
|
||||
/// [`SystemSet`]s for asset loading in an [`App`] schedule.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
|
||||
#[system_set(base)]
|
||||
pub enum AssetSet {
|
||||
/// Asset storages are updated.
|
||||
LoadAssets,
|
||||
/// Asset events are generated.
|
||||
AssetEvents,
|
||||
}
|
||||
/// Asset storages are updated.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)]
|
||||
pub struct LoadAssets;
|
||||
/// Asset events are generated.
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)]
|
||||
pub struct AssetEvents;
|
||||
|
||||
/// Adds support for [`Assets`] to an App.
|
||||
///
|
||||
|
@ -106,24 +103,19 @@ impl Plugin for AssetPlugin {
|
|||
app.insert_resource(asset_server);
|
||||
}
|
||||
|
||||
app.register_type::<HandleId>();
|
||||
|
||||
app.configure_set(
|
||||
AssetSet::LoadAssets
|
||||
.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));
|
||||
app.register_type::<HandleId>()
|
||||
.add_systems(PreUpdate, asset_server::free_unused_assets_system);
|
||||
app.init_schedule(LoadAssets);
|
||||
app.init_schedule(AssetEvents);
|
||||
|
||||
#[cfg(all(
|
||||
feature = "filesystem_watcher",
|
||||
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_audio::{Audio, AudioPlugin};
|
||||
//! # use bevy_asset::{AssetPlugin, AssetServer};
|
||||
//! # use bevy_app::{App, AppExit, NoopPluginGroup as MinimalPlugins};
|
||||
//! # use bevy_app::{App, AppExit, NoopPluginGroup as MinimalPlugins, Startup};
|
||||
//! fn main() {
|
||||
//! App::new()
|
||||
//! .add_plugins(MinimalPlugins)
|
||||
//! .add_plugin(AssetPlugin::default())
|
||||
//! .add_plugin(AudioPlugin)
|
||||
//! .add_startup_system(play_background_audio)
|
||||
//! .add_systems(Startup, play_background_audio)
|
||||
//! .run();
|
||||
//! }
|
||||
//!
|
||||
|
@ -47,7 +47,6 @@ pub use sinks::*;
|
|||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_asset::{AddAsset, Asset};
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
/// Adds support for audio playback to a Bevy Application
|
||||
///
|
||||
|
@ -62,7 +61,7 @@ impl Plugin for AudioPlugin {
|
|||
.add_asset::<AudioSink>()
|
||||
.add_asset::<SpatialAudioSink>()
|
||||
.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"))]
|
||||
app.init_asset_loader::<AudioLoader>();
|
||||
|
@ -78,6 +77,6 @@ impl AddAudioSource for App {
|
|||
self.add_asset::<T>()
|
||||
.init_resource::<Audio<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 {
|
||||
fn build(&self, app: &mut App) {
|
||||
fn build(&self, _app: &mut App) {
|
||||
// Setup the default bevy task pools
|
||||
self.task_pool_options.create_default_pools();
|
||||
|
||||
#[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.
|
||||
|
@ -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.
|
||||
///
|
||||
/// [`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.
|
||||
///
|
||||
/// # Overflows
|
||||
|
@ -142,7 +142,7 @@ pub struct FrameCountPlugin;
|
|||
impl Plugin for FrameCountPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
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 bevy_app::{App, Plugin};
|
||||
use bevy_asset::{load_internal_asset, HandleUntyped};
|
||||
use bevy_ecs::{
|
||||
prelude::{Component, Entity},
|
||||
query::{QueryState, With},
|
||||
schedule::IntoSystemConfig,
|
||||
system::{Commands, Query, Res, ResMut},
|
||||
world::World,
|
||||
};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::UVec2;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_render::{
|
||||
|
@ -27,7 +21,7 @@ use bevy_render::{
|
|||
renderer::{RenderContext, RenderDevice},
|
||||
texture::{CachedTexture, TextureCache},
|
||||
view::ViewTarget,
|
||||
RenderApp, RenderSet,
|
||||
Render, RenderApp, RenderSet,
|
||||
};
|
||||
#[cfg(feature = "trace")]
|
||||
use bevy_utils::tracing::info_span;
|
||||
|
@ -71,12 +65,15 @@ impl Plugin for BloomPlugin {
|
|||
.init_resource::<BloomUpsamplingPipeline>()
|
||||
.init_resource::<SpecializedRenderPipelines<BloomDownsamplingPipeline>>()
|
||||
.init_resource::<SpecializedRenderPipelines<BloomUpsamplingPipeline>>()
|
||||
.add_systems((
|
||||
prepare_bloom_textures.in_set(RenderSet::Prepare),
|
||||
prepare_downsampling_pipeline.in_set(RenderSet::Prepare),
|
||||
prepare_upsampling_pipeline.in_set(RenderSet::Prepare),
|
||||
queue_bloom_bind_groups.in_set(RenderSet::Queue),
|
||||
));
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_bloom_textures.in_set(RenderSet::Prepare),
|
||||
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
|
||||
{
|
||||
|
|
|
@ -20,7 +20,7 @@ pub mod graph {
|
|||
pub use camera_2d::*;
|
||||
pub use main_pass_2d_node::*;
|
||||
|
||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_render::{
|
||||
camera::Camera,
|
||||
|
@ -31,7 +31,7 @@ use bevy_render::{
|
|||
DrawFunctionId, DrawFunctions, PhaseItem, RenderPhase,
|
||||
},
|
||||
render_resource::CachedRenderPipelineId,
|
||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_utils::FloatOrd;
|
||||
use std::ops::Range;
|
||||
|
@ -52,13 +52,16 @@ impl Plugin for Core2dPlugin {
|
|||
|
||||
render_app
|
||||
.init_resource::<DrawFunctions<Transparent2d>>()
|
||||
.add_systems((
|
||||
extract_core_2d_camera_phases.in_schedule(ExtractSchedule),
|
||||
sort_phase_system::<Transparent2d>.in_set(RenderSet::PhaseSort),
|
||||
batch_phase_system::<Transparent2d>
|
||||
.after(sort_phase_system::<Transparent2d>)
|
||||
.in_set(RenderSet::PhaseSort),
|
||||
));
|
||||
.add_systems(ExtractSchedule, extract_core_2d_camera_phases)
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
sort_phase_system::<Transparent2d>.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 tonemapping = TonemappingNode::new(&mut render_app.world);
|
||||
|
|
|
@ -23,7 +23,7 @@ use std::cmp::Reverse;
|
|||
pub use camera_3d::*;
|
||||
pub use main_pass_3d_node::*;
|
||||
|
||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_render::{
|
||||
camera::{Camera, ExtractedCamera},
|
||||
|
@ -41,7 +41,7 @@ use bevy_render::{
|
|||
renderer::RenderDevice,
|
||||
texture::TextureCache,
|
||||
view::ViewDepthTexture,
|
||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_utils::{FloatOrd, HashMap};
|
||||
|
||||
|
@ -68,15 +68,18 @@ impl Plugin for Core3dPlugin {
|
|||
.init_resource::<DrawFunctions<Opaque3d>>()
|
||||
.init_resource::<DrawFunctions<AlphaMask3d>>()
|
||||
.init_resource::<DrawFunctions<Transparent3d>>()
|
||||
.add_systems((
|
||||
extract_core_3d_camera_phases.in_schedule(ExtractSchedule),
|
||||
prepare_core_3d_depth_textures
|
||||
.in_set(RenderSet::Prepare)
|
||||
.after(bevy_render::view::prepare_windows),
|
||||
sort_phase_system::<Opaque3d>.in_set(RenderSet::PhaseSort),
|
||||
sort_phase_system::<AlphaMask3d>.in_set(RenderSet::PhaseSort),
|
||||
sort_phase_system::<Transparent3d>.in_set(RenderSet::PhaseSort),
|
||||
));
|
||||
.add_systems(ExtractSchedule, extract_core_3d_camera_phases)
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_core_3d_depth_textures
|
||||
.in_set(RenderSet::Prepare)
|
||||
.after(bevy_render::view::prepare_windows),
|
||||
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 pass_node_3d = MainPass3dNode::new(&mut render_app.world);
|
||||
|
|
|
@ -14,7 +14,7 @@ use bevy_render::{
|
|||
renderer::RenderDevice,
|
||||
texture::BevyDefault,
|
||||
view::{ExtractedView, ViewTarget},
|
||||
RenderApp, RenderSet,
|
||||
Render, RenderApp, RenderSet,
|
||||
};
|
||||
|
||||
mod node;
|
||||
|
@ -90,7 +90,7 @@ impl Plugin for FxaaPlugin {
|
|||
render_app
|
||||
.init_resource::<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);
|
||||
|
|
|
@ -6,7 +6,7 @@ use bevy_render::{
|
|||
render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext, SlotInfo, SlotType},
|
||||
renderer::RenderContext,
|
||||
view::{Msaa, ViewTarget},
|
||||
RenderSet,
|
||||
Render, RenderSet,
|
||||
};
|
||||
use bevy_render::{render_resource::*, RenderApp};
|
||||
|
||||
|
@ -20,7 +20,10 @@ impl Plugin for MsaaWritebackPlugin {
|
|||
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_3d = MsaaWritebackNode::new(&mut render_app.world);
|
||||
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::texture::{CompressedImageFormats, Image, ImageSampler, ImageType};
|
||||
use bevy_render::view::{ViewTarget, ViewUniform};
|
||||
use bevy_render::{render_resource::*, RenderApp, RenderSet};
|
||||
use bevy_render::{render_resource::*, Render, RenderApp, RenderSet};
|
||||
|
||||
mod node;
|
||||
|
||||
|
@ -94,7 +94,10 @@ impl Plugin for TonemappingPlugin {
|
|||
render_app
|
||||
.init_resource::<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_render::camera::{CameraOutputMode, ExtractedCamera};
|
||||
use bevy_render::view::ViewTarget;
|
||||
use bevy_render::{render_resource::*, RenderApp, RenderSet};
|
||||
use bevy_render::{render_resource::*, Render, RenderApp, RenderSet};
|
||||
|
||||
mod node;
|
||||
|
||||
|
@ -14,7 +14,10 @@ pub struct UpscalingPlugin;
|
|||
impl Plugin for UpscalingPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
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 {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_startup_system(Self::setup_system)
|
||||
.add_system(Self::diagnostic_system);
|
||||
app.add_systems(Startup, Self::setup_system)
|
||||
.add_systems(Update, Self::diagnostic_system);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ pub struct FrameTimeDiagnosticsPlugin;
|
|||
|
||||
impl Plugin for FrameTimeDiagnosticsPlugin {
|
||||
fn build(&self, app: &mut bevy_app::App) {
|
||||
app.add_startup_system(Self::setup_system)
|
||||
.add_system(Self::diagnostic_system);
|
||||
app.add_systems(Startup, Self::setup_system)
|
||||
.add_systems(Update, Self::diagnostic_system);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@ pub struct DiagnosticsPlugin;
|
|||
|
||||
impl Plugin for DiagnosticsPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<Diagnostics>()
|
||||
.add_startup_system(system_information_diagnostics_plugin::internal::log_system_info);
|
||||
app.init_resource::<Diagnostics>().add_systems(
|
||||
Startup,
|
||||
system_information_diagnostics_plugin::internal::log_system_info,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,9 +37,9 @@ impl Plugin for LogDiagnosticsPlugin {
|
|||
});
|
||||
|
||||
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 {
|
||||
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;
|
||||
impl Plugin for SystemInformationDiagnosticsPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_startup_system(internal::setup_system)
|
||||
.add_system(internal::diagnostic_system);
|
||||
app.add_systems(Startup, internal::setup_system)
|
||||
.add_systems(Update, internal::diagnostic_system);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ fn main() {
|
|||
let mut schedule = Schedule::default();
|
||||
|
||||
// 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
|
||||
schedule.run(&mut world);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use bevy_ecs::{prelude::*, schedule::IntoSystemConfig};
|
||||
use bevy_ecs::prelude::*;
|
||||
use rand::Rng;
|
||||
use std::ops::Deref;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
|||
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
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.
|
||||
schedule.add_systems((
|
||||
|
|
|
@ -469,7 +469,7 @@ pub fn derive_schedule_label(input: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
/// 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 {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let mut trait_path = bevy_ecs_path();
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
use proc_macro::TokenStream;
|
||||
use quote::{format_ident, quote, ToTokens};
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
|
||||
pub static SYSTEM_SET_ATTRIBUTE_NAME: &str = "system_set";
|
||||
pub static BASE_ATTRIBUTE_NAME: &str = "base";
|
||||
use quote::quote;
|
||||
|
||||
/// 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
|
||||
/// - `trait_path`: The [`syn::Path`] to the set trait
|
||||
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 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 mut where_clause = where_clause.cloned().unwrap_or_else(|| syn::WhereClause {
|
||||
where_token: Default::default(),
|
||||
|
@ -73,28 +22,12 @@ pub fn derive_set(input: syn::DeriveInput, trait_path: &syn::Path) -> TokenStrea
|
|||
.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! {
|
||||
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> {
|
||||
std::boxed::Box::new(std::clone::Clone::clone(self))
|
||||
}
|
||||
}
|
||||
|
||||
#marker_impl
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
|
|
@ -939,7 +939,7 @@ mod tests {
|
|||
world.send_event(TestEvent { i: 4 });
|
||||
|
||||
let mut schedule = Schedule::new();
|
||||
schedule.add_system(|mut events: EventReader<TestEvent>| {
|
||||
schedule.add_systems(|mut events: EventReader<TestEvent>| {
|
||||
let mut iter = events.iter();
|
||||
|
||||
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
|
||||
|
|
|
@ -39,9 +39,8 @@ pub mod prelude {
|
|||
removal_detection::RemovedComponents,
|
||||
schedule::{
|
||||
apply_state_transition, apply_system_buffers, common_conditions::*, Condition,
|
||||
IntoSystemConfig, IntoSystemConfigs, IntoSystemSet, IntoSystemSetConfig,
|
||||
IntoSystemSetConfigs, NextState, OnEnter, OnExit, OnTransition, OnUpdate, Schedule,
|
||||
Schedules, State, States, SystemSet,
|
||||
IntoSystemConfigs, IntoSystemSet, IntoSystemSetConfig, IntoSystemSetConfigs, NextState,
|
||||
OnEnter, OnExit, OnTransition, OnUpdate, Schedule, Schedules, State, States, SystemSet,
|
||||
},
|
||||
system::{
|
||||
adapter as system_adapter,
|
||||
|
|
|
@ -31,7 +31,7 @@ pub trait Condition<Marker>: sealed::Condition<Marker> {
|
|||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// # fn my_system() {}
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // The `resource_equals` run condition will panic since we don't initialize `R`,
|
||||
/// // just like if we used `Res<R>` in a system.
|
||||
/// 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 world = World::new();
|
||||
/// # fn my_system() {}
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_equals` will only get run if the resource `R` exists.
|
||||
/// 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();
|
||||
/// # #[derive(Resource)] struct C(bool);
|
||||
/// # 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.
|
||||
/// 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 world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `run_once` will only return true the first time it's evaluated
|
||||
/// my_system.run_if(run_once()),
|
||||
/// );
|
||||
|
@ -199,7 +199,7 @@ pub mod common_conditions {
|
|||
/// # struct Counter(u8);
|
||||
/// # let mut app = Schedule::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
|
||||
/// my_system.run_if(resource_exists::<Counter>()),
|
||||
/// );
|
||||
|
@ -239,7 +239,7 @@ pub mod common_conditions {
|
|||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_equals` will only return true if the given resource equals the given value
|
||||
/// my_system.run_if(resource_equals(Counter(0))),
|
||||
/// );
|
||||
|
@ -276,7 +276,7 @@ pub mod common_conditions {
|
|||
/// # struct Counter(u8);
|
||||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_exists_and_equals` will only return true
|
||||
/// // if the given resource exsists and equals the given value
|
||||
/// my_system.run_if(resource_exists_and_equals(Counter(0))),
|
||||
|
@ -319,7 +319,7 @@ pub mod common_conditions {
|
|||
/// # struct Counter(u8);
|
||||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_added` will only return true if the
|
||||
/// // given resource was just added
|
||||
/// my_system.run_if(resource_added::<Counter>()),
|
||||
|
@ -370,7 +370,7 @@ pub mod common_conditions {
|
|||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_changed` will only return true if the
|
||||
/// // given resource was just changed (or added)
|
||||
/// my_system.run_if(
|
||||
|
@ -423,7 +423,7 @@ pub mod common_conditions {
|
|||
/// # struct Counter(u8);
|
||||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_exists_and_changed` will only return true if the
|
||||
/// // given resource exsists and was just changed (or added)
|
||||
/// my_system.run_if(
|
||||
|
@ -485,7 +485,7 @@ pub mod common_conditions {
|
|||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_changed_or_removed` will only return true if the
|
||||
/// // given resource was just changed or removed (or added)
|
||||
/// my_system.run_if(
|
||||
|
@ -555,7 +555,7 @@ pub mod common_conditions {
|
|||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `resource_removed` will only return true if the
|
||||
/// // given resource was just removed
|
||||
/// my_system.run_if(resource_removed::<MyResource>()),
|
||||
|
@ -617,7 +617,7 @@ pub mod common_conditions {
|
|||
/// Paused,
|
||||
/// }
|
||||
///
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `state_exists` will only return true if the
|
||||
/// // given state exsists
|
||||
/// my_system.run_if(state_exists::<GameState>()),
|
||||
|
@ -784,7 +784,7 @@ pub mod common_conditions {
|
|||
///
|
||||
/// world.init_resource::<State<GameState>>();
|
||||
///
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `state_changed` will only return true if the
|
||||
/// // given states value has just been updated or
|
||||
/// // the state has just been added
|
||||
|
@ -826,9 +826,9 @@ pub mod common_conditions {
|
|||
/// # let mut world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// # 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>()),
|
||||
/// );
|
||||
///
|
||||
|
@ -868,7 +868,7 @@ pub mod common_conditions {
|
|||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// my_system.run_if(any_with_component::<MyComponent>()),
|
||||
/// );
|
||||
///
|
||||
|
@ -904,7 +904,7 @@ pub mod common_conditions {
|
|||
/// # let mut app = Schedule::new();
|
||||
/// # let mut world = World::new();
|
||||
/// # world.init_resource::<Counter>();
|
||||
/// app.add_system(
|
||||
/// app.add_systems(
|
||||
/// // `not` will inverse any condition you pass in.
|
||||
/// // Since the condition we choose always returns true
|
||||
/// // this system will never run
|
||||
|
@ -1073,15 +1073,11 @@ where
|
|||
mod tests {
|
||||
use super::{common_conditions::*, Condition};
|
||||
use crate as bevy_ecs;
|
||||
use crate::{
|
||||
change_detection::ResMut,
|
||||
component::Component,
|
||||
schedule::{
|
||||
common_conditions::not, IntoSystemConfig, IntoSystemConfigs, Schedule, State, States,
|
||||
},
|
||||
system::Local,
|
||||
world::World,
|
||||
};
|
||||
use crate::component::Component;
|
||||
use crate::schedule::IntoSystemConfigs;
|
||||
use crate::schedule::{common_conditions::not, State, States};
|
||||
use crate::system::Local;
|
||||
use crate::{change_detection::ResMut, schedule::Schedule, world::World};
|
||||
use bevy_ecs_macros::Resource;
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
|
@ -1103,7 +1099,7 @@ mod tests {
|
|||
let mut schedule = Schedule::new();
|
||||
|
||||
// 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);
|
||||
|
@ -1113,7 +1109,7 @@ mod tests {
|
|||
assert_eq!(world.resource::<Counter>().0, 2);
|
||||
|
||||
// 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);
|
||||
|
@ -1130,9 +1126,9 @@ mod tests {
|
|||
let mut schedule = Schedule::new();
|
||||
|
||||
// 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
|
||||
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);
|
||||
assert_eq!(world.resource::<Counter>().0, 2);
|
||||
|
@ -1147,9 +1143,9 @@ mod tests {
|
|||
let mut schedule = Schedule::new();
|
||||
|
||||
// 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
|
||||
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);
|
||||
assert_eq!(world.resource::<Counter>().0, 1);
|
||||
|
@ -1166,7 +1162,7 @@ mod tests {
|
|||
|
||||
// This should never run, if multiple run conditions worked
|
||||
// like an OR condition then it would always run
|
||||
schedule.add_system(
|
||||
schedule.add_systems(
|
||||
increment_counter
|
||||
.run_if(every_other_time)
|
||||
.run_if(not(every_other_time)),
|
||||
|
|
|
@ -5,57 +5,11 @@ use crate::{
|
|||
condition::{BoxedCondition, Condition},
|
||||
graph_utils::{Ambiguity, Dependency, DependencyKind, GraphInfo},
|
||||
set::{BoxedSystemSet, IntoSystemSet, SystemSet},
|
||||
ScheduleLabel,
|
||||
},
|
||||
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 {
|
||||
let condition_system = IntoSystem::into_system(condition);
|
||||
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`].
|
||||
///
|
||||
/// 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;
|
||||
/// Add to the provided `set`.
|
||||
#[track_caller]
|
||||
fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfig {
|
||||
fn in_set(self, set: impl SystemSet) -> SystemSetConfig {
|
||||
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`.
|
||||
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfig {
|
||||
self.into_config().before(set)
|
||||
|
@ -125,6 +434,35 @@ pub trait IntoSystemSetConfig: Sized {
|
|||
fn ambiguous_with_all(self) -> SystemSetConfig {
|
||||
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 {
|
||||
|
@ -150,41 +488,10 @@ impl IntoSystemSetConfig for SystemSetConfig {
|
|||
set.system_type().is_none(),
|
||||
"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
|
||||
}
|
||||
|
||||
#[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 {
|
||||
self.graph_info.dependencies.push(Dependency::new(
|
||||
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`].
|
||||
pub struct SystemSetConfigs {
|
||||
pub(super) sets: Vec<SystemSetConfig>,
|
||||
|
@ -561,16 +542,10 @@ where
|
|||
|
||||
/// Add these system sets to the provided `set`.
|
||||
#[track_caller]
|
||||
fn in_set(self, set: impl FreeSystemSet) -> SystemSetConfigs {
|
||||
fn in_set(self, set: impl SystemSet) -> SystemSetConfigs {
|
||||
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`.
|
||||
fn before<M>(self, set: impl IntoSystemSet<M>) -> SystemSetConfigs {
|
||||
self.into_configs().before(set)
|
||||
|
@ -599,6 +574,35 @@ where
|
|||
fn chain(self) -> SystemSetConfigs {
|
||||
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 {
|
||||
|
@ -612,42 +616,13 @@ impl IntoSystemSetConfigs for SystemSetConfigs {
|
|||
set.system_type().is_none(),
|
||||
"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 {
|
||||
assert!(
|
||||
!config.set.is_base(),
|
||||
"Base system sets cannot be added to other sets."
|
||||
);
|
||||
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(),
|
||||
"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 {
|
||||
let set = set.into_system_set();
|
||||
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 {
|
||||
($($set: ident),*) => {
|
||||
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);
|
||||
|
|
|
@ -67,56 +67,14 @@ pub(crate) enum Ambiguity {
|
|||
IgnoreAll,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct GraphInfo {
|
||||
pub(crate) sets: Vec<BoxedSystemSet>,
|
||||
pub(crate) dependencies: Vec<Dependency>,
|
||||
pub(crate) ambiguous_with: Ambiguity,
|
||||
pub(crate) add_default_base_set: bool,
|
||||
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.
|
||||
pub(crate) fn index(row: usize, col: usize, num_cols: usize) -> usize {
|
||||
debug_assert!(col < num_cols);
|
||||
|
|
|
@ -23,7 +23,7 @@ mod tests {
|
|||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
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::{prelude::World, system::Resource};
|
||||
|
||||
|
@ -75,7 +75,7 @@ mod tests {
|
|||
|
||||
world.init_resource::<SystemOrder>();
|
||||
|
||||
schedule.add_system(make_function_system(0));
|
||||
schedule.add_systems(make_function_system(0));
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
|
||||
|
@ -88,7 +88,7 @@ mod tests {
|
|||
|
||||
world.init_resource::<SystemOrder>();
|
||||
|
||||
schedule.add_system(make_exclusive_system(0));
|
||||
schedule.add_systems(make_exclusive_system(0));
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert_eq!(world.resource::<SystemOrder>().0, vec![0]);
|
||||
|
@ -108,7 +108,7 @@ mod tests {
|
|||
|
||||
for _ in 0..thread_count {
|
||||
let inner = barrier.clone();
|
||||
schedule.add_system(move || {
|
||||
schedule.add_systems(move || {
|
||||
inner.wait();
|
||||
});
|
||||
}
|
||||
|
@ -195,6 +195,50 @@ mod tests {
|
|||
schedule.run(&mut world);
|
||||
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 {
|
||||
|
@ -210,7 +254,7 @@ mod tests {
|
|||
world.init_resource::<RunConditionBool>();
|
||||
world.init_resource::<SystemOrder>();
|
||||
|
||||
schedule.add_system(
|
||||
schedule.add_systems(
|
||||
make_function_system(0).run_if(|condition: Res<RunConditionBool>| condition.0),
|
||||
);
|
||||
|
||||
|
@ -256,7 +300,7 @@ mod tests {
|
|||
world.init_resource::<RunConditionBool>();
|
||||
world.init_resource::<SystemOrder>();
|
||||
|
||||
schedule.add_system(
|
||||
schedule.add_systems(
|
||||
make_exclusive_system(0).run_if(|condition: Res<RunConditionBool>| condition.0),
|
||||
);
|
||||
|
||||
|
@ -294,13 +338,13 @@ mod tests {
|
|||
world.init_resource::<Counter>();
|
||||
|
||||
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.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.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.add_system(counting_system.in_set(TestSet::D));
|
||||
schedule.add_systems(counting_system.in_set(TestSet::D));
|
||||
|
||||
schedule.run(&mut world);
|
||||
assert_eq!(world.resource::<Counter>().0.load(Ordering::Relaxed), 1);
|
||||
|
@ -314,13 +358,13 @@ mod tests {
|
|||
world.init_resource::<Counter>();
|
||||
|
||||
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.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.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.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);
|
||||
assert_eq!(world.resource::<Counter>().0.load(Ordering::Relaxed), 1);
|
||||
|
@ -337,7 +381,7 @@ mod tests {
|
|||
world.init_resource::<Bool2>();
|
||||
let mut schedule = Schedule::default();
|
||||
|
||||
schedule.add_system(
|
||||
schedule.add_systems(
|
||||
counting_system
|
||||
.run_if(|res1: Res<RunConditionBool>| res1.is_changed())
|
||||
.run_if(|res2: Res<Bool2>| res2.is_changed()),
|
||||
|
@ -391,7 +435,7 @@ mod tests {
|
|||
.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.
|
||||
schedule.run(&mut world);
|
||||
|
@ -438,7 +482,7 @@ mod tests {
|
|||
schedule
|
||||
.configure_set(TestSet::A.run_if(|res1: Res<RunConditionBool>| res1.is_changed()));
|
||||
|
||||
schedule.add_system(
|
||||
schedule.add_systems(
|
||||
counting_system
|
||||
.run_if(|res2: Res<Bool2>| res2.is_changed())
|
||||
.in_set(TestSet::A),
|
||||
|
@ -544,7 +588,7 @@ mod tests {
|
|||
assert!(result.is_ok());
|
||||
|
||||
// Schedule another `foo`.
|
||||
schedule.add_system(foo);
|
||||
schedule.add_systems(foo);
|
||||
|
||||
// When there are multiple instances of `foo`, dependencies on
|
||||
// `foo` are no longer allowed. Too much ambiguity.
|
||||
|
@ -556,11 +600,11 @@ mod tests {
|
|||
|
||||
// same goes for `ambiguous_with`
|
||||
let mut schedule = Schedule::new();
|
||||
schedule.add_system(foo);
|
||||
schedule.add_system(bar.ambiguous_with(foo));
|
||||
schedule.add_systems(foo);
|
||||
schedule.add_systems(bar.ambiguous_with(foo));
|
||||
let result = schedule.initialize(&mut world);
|
||||
assert!(result.is_ok());
|
||||
schedule.add_system(foo);
|
||||
schedule.add_systems(foo);
|
||||
let result = schedule.initialize(&mut world);
|
||||
assert!(matches!(
|
||||
result,
|
||||
|
@ -626,7 +670,7 @@ mod tests {
|
|||
fn foo() {}
|
||||
|
||||
// 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`.
|
||||
schedule.configure_sets((
|
||||
|
@ -664,140 +708,4 @@ mod tests {
|
|||
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.
|
||||
pub fn insert(&mut self, label: impl ScheduleLabel, schedule: Schedule) -> Option<Schedule> {
|
||||
let label = label.dyn_clone();
|
||||
if self.inner.contains_key(&label) {
|
||||
warn!("schedule with label {:?} already exists", label);
|
||||
}
|
||||
self.inner.insert(label, schedule)
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
if !self.inner.contains_key(label) {
|
||||
warn!("schedule with label {:?} not found", label);
|
||||
}
|
||||
self.inner.remove(label)
|
||||
}
|
||||
|
||||
|
@ -62,9 +56,6 @@ impl Schedules {
|
|||
&mut self,
|
||||
label: &dyn ScheduleLabel,
|
||||
) -> Option<(Box<dyn ScheduleLabel>, Schedule)> {
|
||||
if !self.inner.contains_key(label) {
|
||||
warn!("schedule with label {:?} not found", label);
|
||||
}
|
||||
self.inner.remove_entry(label)
|
||||
}
|
||||
|
||||
|
@ -134,7 +125,7 @@ fn make_executor(kind: ExecutorKind) -> Box<dyn SystemExecutor> {
|
|||
/// fn main() {
|
||||
/// let mut world = World::new();
|
||||
/// let mut schedule = Schedule::default();
|
||||
/// schedule.add_system(hello_world);
|
||||
/// schedule.add_systems(hello_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.
|
||||
pub fn add_system<M>(&mut self, system: impl IntoSystemConfig<M>) -> &mut Self {
|
||||
self.graph.add_system(system);
|
||||
#[deprecated(since = "0.11.0", note = "please use `add_systems` instead")]
|
||||
pub fn add_system<M>(&mut self, system: impl IntoSystemConfigs<M>) -> &mut Self {
|
||||
self.graph.add_systems_inner(system.into_configs(), false);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a collection of systems to the schedule.
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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`].
|
||||
struct SystemSetNode {
|
||||
inner: BoxedSystemSet,
|
||||
base_set_membership: BaseSetMembership,
|
||||
}
|
||||
|
||||
impl SystemSetNode {
|
||||
pub fn new(set: BoxedSystemSet) -> Self {
|
||||
Self {
|
||||
inner: set,
|
||||
base_set_membership: BaseSetMembership::Uncalculated,
|
||||
}
|
||||
Self { inner: set }
|
||||
}
|
||||
|
||||
pub fn name(&self) -> String {
|
||||
|
@ -383,14 +354,12 @@ impl SystemSetNode {
|
|||
/// A [`BoxedSystem`] with metadata, stored in a [`ScheduleGraph`].
|
||||
struct SystemNode {
|
||||
inner: Option<BoxedSystem>,
|
||||
base_set_membership: BaseSetMembership,
|
||||
}
|
||||
|
||||
impl SystemNode {
|
||||
pub fn new(system: BoxedSystem) -> Self {
|
||||
Self {
|
||||
inner: Some(system),
|
||||
base_set_membership: BaseSetMembership::Uncalculated,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,10 +370,6 @@ impl SystemNode {
|
|||
pub fn get_mut(&mut self) -> Option<&mut BoxedSystem> {
|
||||
self.inner.as_mut()
|
||||
}
|
||||
|
||||
pub fn name(&self) -> String {
|
||||
format!("{:?}", &self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata for a [`Schedule`].
|
||||
|
@ -416,7 +381,6 @@ pub struct ScheduleGraph {
|
|||
system_set_conditions: Vec<Option<Vec<BoxedCondition>>>,
|
||||
system_set_ids: HashMap<BoxedSystemSet, NodeId>,
|
||||
uninit: Vec<(NodeId, usize)>,
|
||||
maybe_default_base_set: Vec<NodeId>,
|
||||
hierarchy: Dag,
|
||||
dependency: Dag,
|
||||
dependency_flattened: Dag,
|
||||
|
@ -426,7 +390,6 @@ pub struct ScheduleGraph {
|
|||
conflicting_systems: Vec<(NodeId, NodeId, Vec<ComponentId>)>,
|
||||
changed: bool,
|
||||
settings: ScheduleBuildSettings,
|
||||
default_base_set: Option<BoxedSystemSet>,
|
||||
}
|
||||
|
||||
impl ScheduleGraph {
|
||||
|
@ -437,7 +400,6 @@ impl ScheduleGraph {
|
|||
system_sets: Vec::new(),
|
||||
system_set_conditions: Vec::new(),
|
||||
system_set_ids: HashMap::new(),
|
||||
maybe_default_base_set: Vec::new(),
|
||||
uninit: Vec::new(),
|
||||
hierarchy: Dag::new(),
|
||||
dependency: Dag::new(),
|
||||
|
@ -448,7 +410,6 @@ impl ScheduleGraph {
|
|||
conflicting_systems: Vec::new(),
|
||||
changed: false,
|
||||
settings: default(),
|
||||
default_base_set: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,44 +452,29 @@ impl ScheduleGraph {
|
|||
}
|
||||
|
||||
/// 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(
|
||||
&self,
|
||||
) -> impl Iterator<
|
||||
Item = (
|
||||
NodeId,
|
||||
&dyn System<In = (), Out = ()>,
|
||||
BaseSetMembership,
|
||||
&[BoxedCondition],
|
||||
),
|
||||
> {
|
||||
) -> impl Iterator<Item = (NodeId, &dyn System<In = (), Out = ()>, &[BoxedCondition])> {
|
||||
self.systems
|
||||
.iter()
|
||||
.zip(self.system_conditions.iter())
|
||||
.enumerate()
|
||||
.filter_map(|(i, (system_node, condition))| {
|
||||
let system = system_node.inner.as_deref()?;
|
||||
let base_set_membership = system_node.base_set_membership;
|
||||
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.
|
||||
///
|
||||
/// 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])> {
|
||||
pub fn system_sets(&self) -> impl Iterator<Item = (NodeId, &dyn SystemSet, &[BoxedCondition])> {
|
||||
self.system_set_ids.iter().map(|(_, node_id)| {
|
||||
let set_node = &self.system_sets[node_id.index()];
|
||||
let set = &*set_node.inner;
|
||||
let base_set_membership = set_node.base_set_membership;
|
||||
let conditions = self.system_set_conditions[node_id.index()]
|
||||
.as_deref()
|
||||
.unwrap_or(&[]);
|
||||
(*node_id, set, base_set_membership, conditions)
|
||||
(*node_id, set, conditions)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -556,47 +502,144 @@ impl ScheduleGraph {
|
|||
&self.conflicting_systems
|
||||
}
|
||||
|
||||
fn add_systems<M>(&mut self, systems: impl IntoSystemConfigs<M>) {
|
||||
let SystemConfigs { systems, chained } = systems.into_configs();
|
||||
let mut system_iter = systems.into_iter();
|
||||
if chained {
|
||||
let Some(prev) = system_iter.next() else { return };
|
||||
let mut prev_id = self.add_system_inner(prev).unwrap();
|
||||
for next in system_iter {
|
||||
let next_id = self.add_system_inner(next).unwrap();
|
||||
self.dependency.graph.add_edge(prev_id, next_id, ());
|
||||
prev_id = next_id;
|
||||
/// Adds the systems to the graph. Returns a vector of all node ids contained the nested `SystemConfigs`
|
||||
/// if `ancestor_chained` is true. Also returns true if "densely chained", meaning that all nested items
|
||||
/// are linearly chained in the order they are defined
|
||||
fn add_systems_inner(
|
||||
&mut self,
|
||||
configs: SystemConfigs,
|
||||
ancestor_chained: bool,
|
||||
) -> AddSystemsInnerResult {
|
||||
match configs {
|
||||
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 {
|
||||
for system in system_iter {
|
||||
self.add_system_inner(system).unwrap();
|
||||
SystemConfigs::Configs { configs, chained } => {
|
||||
let mut config_iter = configs.into_iter();
|
||||
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>) {
|
||||
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();
|
||||
|
||||
fn add_system_inner(&mut self, config: SystemConfig) -> Result<NodeId, ScheduleBuildError> {
|
||||
let id = NodeId::System(self.systems.len());
|
||||
|
||||
// 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`)
|
||||
self.uninit.push((id, 0));
|
||||
self.systems.push(SystemNode::new(system));
|
||||
self.system_conditions.push(Some(conditions));
|
||||
self.systems.push(SystemNode::new(config.system));
|
||||
self.system_conditions.push(Some(config.conditions));
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
@ -639,7 +682,7 @@ impl ScheduleGraph {
|
|||
};
|
||||
|
||||
// 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`)
|
||||
let system_set_conditions =
|
||||
|
@ -724,7 +767,6 @@ impl ScheduleGraph {
|
|||
&mut self,
|
||||
id: NodeId,
|
||||
graph_info: GraphInfo,
|
||||
is_base_set: bool,
|
||||
) -> Result<(), ScheduleBuildError> {
|
||||
self.check_sets(&id, &graph_info)?;
|
||||
self.check_edges(&id, &graph_info)?;
|
||||
|
@ -734,8 +776,6 @@ impl ScheduleGraph {
|
|||
sets,
|
||||
dependencies,
|
||||
ambiguous_with,
|
||||
base_set,
|
||||
add_default_base_set,
|
||||
..
|
||||
} = graph_info;
|
||||
|
||||
|
@ -749,30 +789,6 @@ impl ScheduleGraph {
|
|||
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) {
|
||||
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`].
|
||||
///
|
||||
/// This method also
|
||||
/// - calculates [`BaseSetMembership`]
|
||||
/// - checks for dependency or hierarchy cycles
|
||||
/// - checks for system access conflicts and reports ambiguities
|
||||
pub fn build_schedule(
|
||||
&mut self,
|
||||
components: &Components,
|
||||
) -> 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
|
||||
self.hierarchy.topsort = self
|
||||
.topsort_graph(&self.hierarchy.graph, ReportCycles::Hierarchy)
|
||||
|
@ -1340,17 +1222,14 @@ impl ScheduleGraph {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn set_default_base_set(&mut self, set: Option<BoxedSystemSet>) {
|
||||
if let Some(set) = set {
|
||||
self.default_base_set = Some(set.dyn_clone());
|
||||
if self.system_set_ids.get(&set).is_none() {
|
||||
self.add_set(set);
|
||||
}
|
||||
} else {
|
||||
self.default_base_set = None;
|
||||
}
|
||||
}
|
||||
/// Values returned by `ScheduleGraph::add_systems_inner`
|
||||
struct AddSystemsInnerResult {
|
||||
/// All nodes contained inside this add_systems_inner call's SystemConfigs hierarchy
|
||||
nodes: Vec<NodeId>,
|
||||
/// True if and only if all nodes are "densely chained"
|
||||
densely_chained: bool,
|
||||
}
|
||||
|
||||
/// Used to select the appropriate reporting function.
|
||||
|
|
|
@ -23,34 +23,10 @@ pub trait SystemSet: DynHash + Debug + Send + Sync + 'static {
|
|||
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.
|
||||
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 {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.dyn_eq(other.as_dyn_eq())
|
||||
|
|
|
@ -50,7 +50,7 @@ use super::{ReadOnlySystem, System};
|
|||
/// # world.init_resource::<RanFlag>();
|
||||
/// #
|
||||
/// # 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(B(1))),
|
||||
/// // The name of the combined system.
|
||||
|
|
|
@ -582,9 +582,9 @@ impl<'w, 's> Commands<'w, 's> {
|
|||
/// # world.init_resource::<Counter>();
|
||||
/// #
|
||||
/// # let mut setup_schedule = Schedule::new();
|
||||
/// # setup_schedule.add_system(setup);
|
||||
/// # setup_schedule.add_systems(setup);
|
||||
/// # let mut assert_schedule = Schedule::new();
|
||||
/// # assert_schedule.add_system(assert_names);
|
||||
/// # assert_schedule.add_systems(assert_names);
|
||||
/// #
|
||||
/// # setup_schedule.run(&mut world);
|
||||
/// # assert_schedule.run(&mut world);
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
//!
|
||||
//! // Configure this system to run in between the other two systems
|
||||
//! // 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!"
|
||||
//! schedule.run(&mut world);
|
||||
//!
|
||||
|
@ -214,7 +214,7 @@ mod tests {
|
|||
|
||||
fn run_system<Marker, S: IntoSystem<(), (), Marker>>(world: &mut World, system: S) {
|
||||
let mut schedule = Schedule::default();
|
||||
schedule.add_system(system);
|
||||
schedule.add_systems(system);
|
||||
schedule.run(world);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ use std::borrow::Cow;
|
|||
///
|
||||
/// Systems are executed in parallel, in opportunistic order; data access is managed automatically.
|
||||
/// 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 {
|
||||
/// The system's input. See [`In`](crate::system::In) for
|
||||
/// [`FunctionSystem`](crate::system::FunctionSystem)s.
|
||||
|
|
|
@ -674,7 +674,7 @@ unsafe impl SystemParam for &'_ World {
|
|||
/// 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)));
|
||||
/// ```
|
||||
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...
|
||||
/// let mut sched = Schedule::default();
|
||||
/// sched.add_system(
|
||||
/// sched.add_systems(
|
||||
/// // Panic if the load system returns an error.
|
||||
/// load_save_system.pipe(system_adapter::unwrap)
|
||||
/// )
|
||||
|
@ -169,7 +169,7 @@ pub mod adapter {
|
|||
///
|
||||
/// // Building a new schedule/app...
|
||||
/// let mut sched = Schedule::default();
|
||||
/// sched.add_system(
|
||||
/// sched.add_systems(
|
||||
/// // Prints system information.
|
||||
/// data_pipe_system.pipe(system_adapter::info)
|
||||
/// )
|
||||
|
@ -196,7 +196,7 @@ pub mod adapter {
|
|||
///
|
||||
/// // Building a new schedule/app...
|
||||
/// let mut sched = Schedule::default();
|
||||
/// sched.add_system(
|
||||
/// sched.add_systems(
|
||||
/// // Prints debug data from system.
|
||||
/// parse_message_system.pipe(system_adapter::dbg)
|
||||
/// )
|
||||
|
@ -223,7 +223,7 @@ pub mod adapter {
|
|||
///
|
||||
/// // Building a new schedule/app...
|
||||
/// # let mut sched = Schedule::default();
|
||||
/// sched.add_system(
|
||||
/// sched.add_systems(
|
||||
/// // Prints system warning if system returns an error.
|
||||
/// warning_pipe_system.pipe(system_adapter::warn)
|
||||
/// )
|
||||
|
@ -251,7 +251,7 @@ pub mod adapter {
|
|||
/// use bevy_ecs::prelude::*;
|
||||
/// // Building a new schedule/app...
|
||||
/// let mut sched = Schedule::default();
|
||||
/// sched.add_system(
|
||||
/// sched.add_systems(
|
||||
/// // Prints system error if system fails.
|
||||
/// parse_error_message_system.pipe(system_adapter::error)
|
||||
/// )
|
||||
|
@ -287,7 +287,7 @@ pub mod adapter {
|
|||
///
|
||||
/// // Building a new schedule/app...
|
||||
/// # let mut sched = Schedule::default(); sched
|
||||
/// .add_system(
|
||||
/// .add_systems(
|
||||
/// // If the system fails, just move on and try again next frame.
|
||||
/// fallible_system.pipe(system_adapter::ignore)
|
||||
/// )
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
mod converter;
|
||||
mod gilrs_system;
|
||||
|
||||
use bevy_app::{App, CoreSet, Plugin, StartupSet};
|
||||
use bevy_app::{App, Plugin, PreStartup, PreUpdate};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_input::InputSystem;
|
||||
use bevy_utils::tracing::error;
|
||||
|
@ -20,14 +20,8 @@ impl Plugin for GilrsPlugin {
|
|||
{
|
||||
Ok(gilrs) => {
|
||||
app.insert_non_send_resource(gilrs)
|
||||
.add_startup_system(
|
||||
gilrs_event_startup_system.in_base_set(StartupSet::PreStartup),
|
||||
)
|
||||
.add_system(
|
||||
gilrs_event_system
|
||||
.before(InputSystem)
|
||||
.in_base_set(CoreSet::PreUpdate),
|
||||
);
|
||||
.add_systems(PreStartup, gilrs_event_startup_system)
|
||||
.add_systems(PreUpdate, gilrs_event_system.before(InputSystem));
|
||||
}
|
||||
Err(err) => error!("Failed to start Gilrs. {}", err),
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use bevy_app::{App, CoreSet, Plugin};
|
||||
use bevy_app::{App, Last, Plugin};
|
||||
use bevy_core::Name;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_log::warn;
|
||||
|
@ -96,10 +96,10 @@ impl<T: Component> Default for ValidParentCheckPlugin<T> {
|
|||
|
||||
impl<T: Component> Plugin for ValidParentCheckPlugin<T> {
|
||||
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>
|
||||
.run_if(resource_equals(ReportHierarchyIssue::<T>::new(true)))
|
||||
.in_base_set(CoreSet::Last),
|
||||
.run_if(resource_equals(ReportHierarchyIssue::<T>::new(true))),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::hash::Hash;
|
|||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .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();
|
||||
/// }
|
||||
///
|
||||
|
@ -33,7 +33,7 @@ use std::hash::Hash;
|
|||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .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();
|
||||
/// }
|
||||
///
|
||||
|
@ -75,7 +75,7 @@ where
|
|||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .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();
|
||||
/// }
|
||||
///
|
||||
|
|
|
@ -53,18 +53,18 @@ pub struct InputSystem;
|
|||
|
||||
impl Plugin for InputPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.configure_set(InputSystem.in_base_set(CoreSet::PreUpdate))
|
||||
app
|
||||
// keyboard
|
||||
.add_event::<KeyboardInput>()
|
||||
.init_resource::<Input<KeyCode>>()
|
||||
.init_resource::<Input<ScanCode>>()
|
||||
.add_system(keyboard_input_system.in_set(InputSystem))
|
||||
.add_systems(PreUpdate, keyboard_input_system.in_set(InputSystem))
|
||||
// mouse
|
||||
.add_event::<MouseButtonInput>()
|
||||
.add_event::<MouseMotion>()
|
||||
.add_event::<MouseWheel>()
|
||||
.init_resource::<Input<MouseButton>>()
|
||||
.add_system(mouse_button_input_system.in_set(InputSystem))
|
||||
.add_systems(PreUpdate, mouse_button_input_system.in_set(InputSystem))
|
||||
// gamepad
|
||||
.add_event::<GamepadConnectionEvent>()
|
||||
.add_event::<GamepadButtonChangedEvent>()
|
||||
|
@ -76,6 +76,7 @@ impl Plugin for InputPlugin {
|
|||
.init_resource::<Axis<GamepadAxis>>()
|
||||
.init_resource::<Axis<GamepadButton>>()
|
||||
.add_systems(
|
||||
PreUpdate,
|
||||
(
|
||||
gamepad_event_system,
|
||||
gamepad_connection_system.after(gamepad_event_system),
|
||||
|
@ -91,7 +92,7 @@ impl Plugin for InputPlugin {
|
|||
// touch
|
||||
.add_event::<TouchInput>()
|
||||
.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
|
||||
app.register_type::<ButtonState>();
|
||||
|
|
|
@ -55,7 +55,7 @@ use bevy_render::{
|
|||
render_phase::sort_phase_system,
|
||||
render_resource::Shader,
|
||||
view::{ViewSet, VisibilitySystems},
|
||||
ExtractSchedule, RenderApp, RenderSet,
|
||||
ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_transform::TransformSystem;
|
||||
use environment_map::EnvironmentMapPlugin;
|
||||
|
@ -176,59 +176,58 @@ impl Plugin for PbrPlugin {
|
|||
.init_resource::<PointLightShadowMap>()
|
||||
.add_plugin(ExtractResourcePlugin::<AmbientLight>::default())
|
||||
.configure_sets(
|
||||
PostUpdate,
|
||||
(
|
||||
SimulationLightSystems::AddClusters,
|
||||
SimulationLightSystems::AddClustersFlush
|
||||
.after(SimulationLightSystems::AddClusters)
|
||||
.before(SimulationLightSystems::AssignLightsToClusters),
|
||||
SimulationLightSystems::AddClustersFlush,
|
||||
SimulationLightSystems::AssignLightsToClusters,
|
||||
SimulationLightSystems::CheckLightVisibility,
|
||||
SimulationLightSystems::UpdateDirectionalLightCascades,
|
||||
SimulationLightSystems::UpdateLightFrusta,
|
||||
)
|
||||
.in_base_set(CoreSet::PostUpdate),
|
||||
.chain(),
|
||||
)
|
||||
.add_plugin(FogPlugin)
|
||||
.add_systems((
|
||||
add_clusters.in_set(SimulationLightSystems::AddClusters),
|
||||
apply_system_buffers.in_set(SimulationLightSystems::AddClustersFlush),
|
||||
assign_lights_to_clusters
|
||||
.in_set(SimulationLightSystems::AssignLightsToClusters)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(VisibilitySystems::CheckVisibility)
|
||||
.after(CameraUpdateSystem),
|
||||
update_directional_light_cascades
|
||||
.in_set(SimulationLightSystems::UpdateDirectionalLightCascades)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(CameraUpdateSystem),
|
||||
update_directional_light_frusta
|
||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||
// This must run after CheckVisibility because it relies on ComputedVisibility::is_visible()
|
||||
.after(VisibilitySystems::CheckVisibility)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::UpdateDirectionalLightCascades)
|
||||
// We assume that no entity will be both a directional light and a spot light,
|
||||
// so these systems will run independently of one another.
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(update_spot_light_frusta),
|
||||
update_point_light_frusta
|
||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::AssignLightsToClusters),
|
||||
update_spot_light_frusta
|
||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::AssignLightsToClusters),
|
||||
check_light_mesh_visibility
|
||||
.in_set(SimulationLightSystems::CheckLightVisibility)
|
||||
.after(VisibilitySystems::CalculateBoundsFlush)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::UpdateLightFrusta)
|
||||
// NOTE: This MUST be scheduled AFTER the core renderer visibility check
|
||||
// because that resets entity ComputedVisibility for the first view
|
||||
// which would override any results from this otherwise
|
||||
.after(VisibilitySystems::CheckVisibility),
|
||||
));
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
(
|
||||
add_clusters.in_set(SimulationLightSystems::AddClusters),
|
||||
apply_system_buffers.in_set(SimulationLightSystems::AddClustersFlush),
|
||||
assign_lights_to_clusters
|
||||
.in_set(SimulationLightSystems::AssignLightsToClusters)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(VisibilitySystems::CheckVisibility)
|
||||
.after(CameraUpdateSystem),
|
||||
update_directional_light_cascades
|
||||
.in_set(SimulationLightSystems::UpdateDirectionalLightCascades)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(CameraUpdateSystem),
|
||||
update_directional_light_frusta
|
||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||
// This must run after CheckVisibility because it relies on ComputedVisibility::is_visible()
|
||||
.after(VisibilitySystems::CheckVisibility)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::UpdateDirectionalLightCascades)
|
||||
// We assume that no entity will be both a directional light and a spot light,
|
||||
// so these systems will run independently of one another.
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(update_spot_light_frusta),
|
||||
update_point_light_frusta
|
||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::AssignLightsToClusters),
|
||||
update_spot_light_frusta
|
||||
.in_set(SimulationLightSystems::UpdateLightFrusta)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::AssignLightsToClusters),
|
||||
check_light_mesh_visibility
|
||||
.in_set(SimulationLightSystems::CheckLightVisibility)
|
||||
.after(VisibilitySystems::CalculateBoundsFlush)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.after(SimulationLightSystems::UpdateLightFrusta)
|
||||
// NOTE: This MUST be scheduled AFTER the core renderer visibility check
|
||||
// because that resets entity ComputedVisibility for the first view
|
||||
// which would override any results from this otherwise
|
||||
.after(VisibilitySystems::CheckVisibility),
|
||||
),
|
||||
);
|
||||
|
||||
app.world
|
||||
.resource_mut::<Assets<StandardMaterial>>()
|
||||
|
@ -248,31 +247,39 @@ impl Plugin for PbrPlugin {
|
|||
|
||||
// Extract the required data from the main world
|
||||
render_app
|
||||
.configure_set(RenderLightSystems::PrepareLights.in_set(RenderSet::Prepare))
|
||||
.configure_set(RenderLightSystems::PrepareClusters.in_set(RenderSet::Prepare))
|
||||
.configure_set(RenderLightSystems::QueueShadows.in_set(RenderSet::Queue))
|
||||
.configure_sets(
|
||||
Render,
|
||||
(
|
||||
RenderLightSystems::PrepareLights.in_set(RenderSet::Prepare),
|
||||
RenderLightSystems::PrepareClusters.in_set(RenderSet::Prepare),
|
||||
RenderLightSystems::QueueShadows.in_set(RenderSet::Queue),
|
||||
),
|
||||
)
|
||||
.add_systems(
|
||||
ExtractSchedule,
|
||||
(
|
||||
render::extract_clusters.in_set(RenderLightSystems::ExtractClusters),
|
||||
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::<LightMeta>()
|
||||
.init_resource::<GlobalLightMeta>();
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
|||
MeshUniform, PrepassPipelinePlugin, PrepassPlugin, RenderLightSystems, SetMeshBindGroup,
|
||||
SetMeshViewBindGroup, Shadow,
|
||||
};
|
||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{AddAsset, AssetEvent, AssetServer, Assets, Handle};
|
||||
use bevy_core_pipeline::{
|
||||
core_3d::{AlphaMask3d, Opaque3d, Transparent3d},
|
||||
|
@ -35,7 +35,7 @@ use bevy_render::{
|
|||
renderer::RenderDevice,
|
||||
texture::FallbackImage,
|
||||
view::{ExtractedView, Msaa, VisibleEntities},
|
||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_utils::{tracing::error, HashMap, HashSet};
|
||||
use std::hash::Hash;
|
||||
|
@ -199,14 +199,17 @@ where
|
|||
.init_resource::<ExtractedMaterials<M>>()
|
||||
.init_resource::<RenderMaterials<M>>()
|
||||
.init_resource::<SpecializedMeshPipelines<MaterialPipeline<M>>>()
|
||||
.add_systems((
|
||||
extract_materials::<M>.in_schedule(ExtractSchedule),
|
||||
prepare_materials::<M>
|
||||
.in_set(RenderSet::Prepare)
|
||||
.after(PrepareAssetSet::PreAssetPrepare),
|
||||
render::queue_shadows::<M>.in_set(RenderLightSystems::QueueShadows),
|
||||
queue_material_meshes::<M>.in_set(RenderSet::Queue),
|
||||
));
|
||||
.add_systems(ExtractSchedule, extract_materials::<M>)
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_materials::<M>
|
||||
.in_set(RenderSet::Prepare)
|
||||
.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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use bevy_app::{IntoSystemAppConfig, Plugin};
|
||||
use bevy_app::Plugin;
|
||||
use bevy_asset::{load_internal_asset, AssetServer, Handle, HandleUntyped};
|
||||
use bevy_core_pipeline::{
|
||||
prelude::Camera3d,
|
||||
|
@ -39,7 +39,7 @@ use bevy_render::{
|
|||
renderer::RenderDevice,
|
||||
texture::{FallbackImagesDepth, FallbackImagesMsaa, TextureCache},
|
||||
view::{ExtractedView, Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, VisibleEntities},
|
||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_utils::{tracing::error, HashMap};
|
||||
|
||||
|
@ -102,7 +102,10 @@ where
|
|||
};
|
||||
|
||||
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::<PrepassViewBindGroup>()
|
||||
.init_resource::<SpecializedMeshPipelines<PrepassPipeline<M>>>();
|
||||
|
@ -130,15 +133,18 @@ where
|
|||
};
|
||||
|
||||
render_app
|
||||
.add_systems((
|
||||
extract_camera_prepass_phase.in_schedule(ExtractSchedule),
|
||||
prepare_prepass_textures
|
||||
.in_set(RenderSet::Prepare)
|
||||
.after(bevy_render::view::prepare_windows),
|
||||
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),
|
||||
))
|
||||
.add_systems(ExtractSchedule, extract_camera_prepass_phase)
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_prepass_textures
|
||||
.in_set(RenderSet::Prepare)
|
||||
.after(bevy_render::view::prepare_windows),
|
||||
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<AlphaMask3dPrepass>>()
|
||||
.add_render_command::<Opaque3dPrepass, DrawPrepass<M>>()
|
||||
|
|
|
@ -8,7 +8,7 @@ use bevy_render::{
|
|||
render_resource::{DynamicUniformBuffer, Shader, ShaderType},
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
view::ExtractedView,
|
||||
RenderApp, RenderSet,
|
||||
Render, RenderApp, RenderSet,
|
||||
};
|
||||
|
||||
use crate::{FogFalloff, FogSettings};
|
||||
|
@ -142,8 +142,11 @@ impl Plugin for FogPlugin {
|
|||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<FogMeta>()
|
||||
.add_system(prepare_fog.in_set(RenderFogSystems::PrepareFog))
|
||||
.configure_set(RenderFogSystems::PrepareFog.in_set(RenderSet::Prepare));
|
||||
.add_systems(Render, prepare_fog.in_set(RenderFogSystems::PrepareFog))
|
||||
.configure_set(
|
||||
Render,
|
||||
RenderFogSystems::PrepareFog.in_set(RenderSet::Prepare),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
ViewClusterBindings, ViewFogUniformOffset, ViewLightsUniformOffset, ViewShadowBindings,
|
||||
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_core_pipeline::{
|
||||
prepass::ViewPrepassTextures,
|
||||
|
@ -36,7 +36,7 @@ use bevy_render::{
|
|||
FallbackImagesMsaa, GpuImage, Image, ImageSampler, TextureFormatPixelInfo,
|
||||
},
|
||||
view::{ComputedVisibility, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms},
|
||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use std::num::NonZeroU64;
|
||||
|
@ -107,12 +107,15 @@ impl Plugin for MeshRenderPlugin {
|
|||
render_app
|
||||
.init_resource::<MeshPipeline>()
|
||||
.init_resource::<SkinnedMeshUniform>()
|
||||
.add_systems((extract_meshes, extract_skinned_meshes).in_schedule(ExtractSchedule))
|
||||
.add_systems((
|
||||
prepare_skinned_meshes.in_set(RenderSet::Prepare),
|
||||
queue_mesh_bind_group.in_set(RenderSet::Queue),
|
||||
queue_mesh_view_bind_groups.in_set(RenderSet::Queue),
|
||||
));
|
||||
.add_systems(ExtractSchedule, (extract_meshes, extract_skinned_meshes))
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
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::{Reflect, TypeUuid};
|
||||
use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin};
|
||||
use bevy_render::Render;
|
||||
use bevy_render::{
|
||||
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||
mesh::{Mesh, MeshVertexBufferLayout},
|
||||
|
@ -47,7 +48,7 @@ impl Plugin for WireframePlugin {
|
|||
.add_render_command::<Opaque3d, DrawWireframes>()
|
||||
.init_resource::<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
|
||||
/// [`OrthographicProjection`] and [`PerspectiveProjection`] are automatically added to
|
||||
/// 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
|
||||
///
|
||||
|
@ -502,7 +502,6 @@ impl NormalizedRenderTarget {
|
|||
/// [`OrthographicProjection`]: crate::camera::OrthographicProjection
|
||||
/// [`PerspectiveProjection`]: crate::camera::PerspectiveProjection
|
||||
/// [`Projection`]: crate::camera::Projection
|
||||
/// [`CoreSet::PostUpdate`]: bevy_app::CoreSet::PostUpdate
|
||||
pub fn camera_system<T: CameraProjection + Component>(
|
||||
mut window_resized_events: EventReader<WindowResized>,
|
||||
mut window_created_events: EventReader<WindowCreated>,
|
||||
|
|
|
@ -7,9 +7,9 @@ pub use camera::*;
|
|||
pub use camera_driver_node::*;
|
||||
pub use projection::*;
|
||||
|
||||
use crate::{render_graph::RenderGraph, ExtractSchedule, RenderApp, RenderSet};
|
||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
||||
use bevy_ecs::schedule::IntoSystemConfig;
|
||||
use crate::{render_graph::RenderGraph, ExtractSchedule, Render, RenderApp, RenderSet};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CameraPlugin;
|
||||
|
@ -29,8 +29,8 @@ impl Plugin for CameraPlugin {
|
|||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<SortedCameras>()
|
||||
.add_system(extract_cameras.in_schedule(ExtractSchedule))
|
||||
.add_system(sort_cameras.in_set(RenderSet::Prepare));
|
||||
.add_systems(ExtractSchedule, extract_cameras)
|
||||
.add_systems(Render, sort_cameras.in_set(RenderSet::Prepare));
|
||||
let camera_driver_node = CameraDriverNode::new(&mut render_app.world);
|
||||
let mut render_graph = render_app.world.resource_mut::<RenderGraph>();
|
||||
render_graph.add_node(crate::main_graph::node::CAMERA_DRIVER, camera_driver_node);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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_math::{Mat4, Rect, Vec2};
|
||||
use bevy_reflect::{
|
||||
|
@ -27,25 +27,24 @@ pub struct CameraUpdateSystem;
|
|||
impl<T: CameraProjection + Component + GetTypeRegistration> Plugin for CameraProjectionPlugin<T> {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_type::<T>()
|
||||
.edit_schedule(CoreSchedule::Startup, |schedule| {
|
||||
schedule.configure_set(CameraUpdateSystem.in_base_set(StartupSet::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),
|
||||
.add_systems(
|
||||
PostStartup,
|
||||
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),
|
||||
));
|
||||
)
|
||||
.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},
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
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_ecs::{
|
||||
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) {
|
||||
render_app
|
||||
.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) {
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
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 {
|
||||
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 bevy_app::{App, IntoSystemAppConfig, Plugin};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::prelude::*;
|
||||
pub use bevy_render_macros::ExtractResource;
|
||||
|
||||
|
@ -32,7 +32,7 @@ impl<R: ExtractResource> Default for ExtractResourcePlugin<R> {
|
|||
impl<R: ExtractResource> Plugin for ExtractResourcePlugin<R> {
|
||||
fn build(&self, app: &mut App) {
|
||||
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,
|
||||
render_resource::{ShaderType, UniformBuffer},
|
||||
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_core::FrameCount;
|
||||
use bevy_ecs::prelude::*;
|
||||
|
@ -26,8 +26,8 @@ impl Plugin for GlobalsPlugin {
|
|||
render_app
|
||||
.init_resource::<GlobalsBuffer>()
|
||||
.init_resource::<Time>()
|
||||
.add_systems((extract_frame_count, extract_time).in_schedule(ExtractSchedule))
|
||||
.add_system(prepare_globals_buffer.in_set(RenderSet::Prepare));
|
||||
.add_systems(ExtractSchedule, (extract_frame_count, extract_time))
|
||||
.add_systems(Render, prepare_globals_buffer.in_set(RenderSet::Prepare));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ use crate::{
|
|||
settings::WgpuSettings,
|
||||
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_ecs::{prelude::*, schedule::ScheduleLabel, system::SystemState};
|
||||
use bevy_utils::tracing::debug;
|
||||
|
@ -101,7 +101,11 @@ pub enum RenderSet {
|
|||
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`].
|
||||
///
|
||||
/// 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())
|
||||
.init_resource::<ScratchMainWorld>();
|
||||
|
||||
let pipeline_cache = PipelineCache::new(device.clone());
|
||||
let asset_server = app.world.resource::<AssetServer>().clone();
|
||||
|
||||
let mut render_app = App::empty();
|
||||
render_app.add_simple_outer_schedule();
|
||||
let mut render_schedule = RenderSet::base_schedule();
|
||||
render_app.main_schedule_label = Box::new(Render);
|
||||
|
||||
// Prepare the schedule which extracts data from the main world to the render world
|
||||
render_app.edit_schedule(ExtractSchedule, |schedule| {
|
||||
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));
|
||||
let mut extract_schedule = Schedule::new();
|
||||
extract_schedule.set_apply_final_buffers(false);
|
||||
|
||||
render_app
|
||||
.add_schedule(CoreSchedule::Main, render_schedule)
|
||||
.add_schedule(ExtractSchedule, extract_schedule)
|
||||
.add_schedule(Render, Render::base_schedule())
|
||||
.init_resource::<render_graph::RenderGraph>()
|
||||
.insert_resource(RenderInstance(instance))
|
||||
.insert_resource(PipelineCache::new(device.clone()))
|
||||
.insert_resource(device)
|
||||
.insert_resource(queue)
|
||||
.insert_resource(render_adapter)
|
||||
.insert_resource(adapter_info)
|
||||
.insert_resource(pipeline_cache)
|
||||
.insert_resource(asset_server);
|
||||
.insert_resource(app.world.resource::<AssetServer>().clone())
|
||||
.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();
|
||||
app.insert_resource(receiver);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use async_channel::{Receiver, Sender};
|
||||
|
||||
use bevy_app::{App, AppLabel, CoreSchedule, Plugin, SubApp};
|
||||
use bevy_app::{App, AppLabel, Main, Plugin, SubApp};
|
||||
use bevy_ecs::{
|
||||
schedule::MainThreadExecutor,
|
||||
system::Resource,
|
||||
|
@ -72,8 +72,7 @@ impl Plugin for PipelinedRenderingPlugin {
|
|||
app.insert_resource(MainThreadExecutor::new());
|
||||
|
||||
let mut sub_app = App::empty();
|
||||
sub_app.add_simple_outer_schedule();
|
||||
sub_app.init_schedule(CoreSchedule::Main);
|
||||
sub_app.init_schedule(Main);
|
||||
app.insert_sub_app(RenderExtractApp, SubApp::new(sub_app, update_rendering));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{Extract, ExtractSchedule, RenderApp, RenderSet};
|
||||
use bevy_app::{App, IntoSystemAppConfig, Plugin};
|
||||
use crate::{Extract, ExtractSchedule, Render, RenderApp, RenderSet};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{Asset, AssetEvent, Assets, Handle};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
|
@ -80,7 +80,12 @@ impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
|||
fn build(&self, app: &mut App) {
|
||||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<ExtractedAssets<A>>()
|
||||
.init_resource::<RenderAssets<A>>()
|
||||
.init_resource::<PrepareNextFrameAssets<A>>()
|
||||
.add_systems(ExtractSchedule, extract_render_asset::<A>)
|
||||
.configure_sets(
|
||||
Render,
|
||||
(
|
||||
PrepareAssetSet::PreAssetPrepare,
|
||||
PrepareAssetSet::AssetPrepare,
|
||||
|
@ -89,13 +94,10 @@ impl<A: RenderAsset> Plugin for RenderAssetPlugin<A> {
|
|||
.chain()
|
||||
.in_set(RenderSet::Prepare),
|
||||
)
|
||||
.init_resource::<ExtractedAssets<A>>()
|
||||
.init_resource::<RenderAssets<A>>()
|
||||
.init_resource::<PrepareNextFrameAssets<A>>()
|
||||
.add_systems((
|
||||
extract_render_asset::<A>.in_schedule(ExtractSchedule),
|
||||
.add_systems(
|
||||
Render,
|
||||
prepare_assets::<A>.in_set(self.prepare_asset_set.clone()),
|
||||
));
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ pub use texture_cache::*;
|
|||
use crate::{
|
||||
render_asset::{PrepareAssetSet, RenderAssetPlugin},
|
||||
renderer::RenderDevice,
|
||||
RenderApp, RenderSet,
|
||||
Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{AddAsset, Assets};
|
||||
|
@ -115,7 +115,10 @@ impl Plugin for ImagePlugin {
|
|||
.init_resource::<FallbackImageCubemap>()
|
||||
.init_resource::<FallbackImageMsaaCache>()
|
||||
.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},
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
texture::{BevyDefault, TextureCache},
|
||||
RenderApp, RenderSet,
|
||||
Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::prelude::*;
|
||||
|
@ -55,14 +55,17 @@ impl Plugin for ViewPlugin {
|
|||
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
||||
render_app
|
||||
.init_resource::<ViewUniforms>()
|
||||
.configure_set(ViewSet::PrepareUniforms.in_set(RenderSet::Prepare))
|
||||
.add_systems((
|
||||
prepare_view_uniforms.in_set(ViewSet::PrepareUniforms),
|
||||
prepare_view_targets
|
||||
.after(WindowSystem::Prepare)
|
||||
.in_set(RenderSet::Prepare)
|
||||
.after(crate::render_asset::prepare_assets::<Image>),
|
||||
));
|
||||
.configure_set(Render, ViewSet::PrepareUniforms.in_set(RenderSet::Prepare))
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_view_uniforms.in_set(ViewSet::PrepareUniforms),
|
||||
prepare_view_targets
|
||||
.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::*;
|
||||
|
||||
use bevy_app::{CoreSet, Plugin};
|
||||
use bevy_app::{Plugin, PostUpdate};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_ecs::prelude::*;
|
||||
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`]
|
||||
/// 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.
|
||||
/// Reading it during [`CoreSet::Update`] will yield the value from the previous frame.
|
||||
/// This value is updated in [`PostUpdate`] by the [`VisibilitySystems::CheckVisibility`] system set.
|
||||
/// Reading it during [`Update`](bevy_app::Update) will yield the value from the previous frame.
|
||||
#[inline]
|
||||
pub fn is_visible(&self) -> bool {
|
||||
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.
|
||||
/// 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]
|
||||
pub fn is_visible_in_hierarchy(&self) -> bool {
|
||||
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
|
||||
/// 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`].
|
||||
/// Each entity type then chooses how to set this field in the [`VisibilitySystems::CheckVisibility`] system set, under [`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, in [`PostUpdate`].
|
||||
/// Meshes might use frustum culling to decide if they are visible in a view.
|
||||
/// Other entities might just set this to `true` every frame.
|
||||
#[inline]
|
||||
|
@ -210,52 +210,49 @@ impl Plugin for VisibilityPlugin {
|
|||
fn build(&self, app: &mut bevy_app::App) {
|
||||
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.
|
||||
.add_system(apply_system_buffers.in_set(CalculateBoundsFlush))
|
||||
.configure_set(
|
||||
CalculateBoundsFlush
|
||||
.after(CalculateBounds)
|
||||
.in_base_set(CoreSet::PostUpdate),
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
apply_system_buffers.in_set(CalculateBoundsFlush),
|
||||
)
|
||||
.configure_set(UpdateOrthographicFrusta.in_base_set(CoreSet::PostUpdate))
|
||||
.configure_set(UpdatePerspectiveFrusta.in_base_set(CoreSet::PostUpdate))
|
||||
.configure_set(UpdateProjectionFrusta.in_base_set(CoreSet::PostUpdate))
|
||||
.configure_set(CheckVisibility.in_base_set(CoreSet::PostUpdate))
|
||||
.configure_set(VisibilityPropagate.in_base_set(CoreSet::PostUpdate))
|
||||
.add_systems((
|
||||
calculate_bounds.in_set(CalculateBounds),
|
||||
update_frusta::<OrthographicProjection>
|
||||
.in_set(UpdateOrthographicFrusta)
|
||||
.after(camera_system::<OrthographicProjection>)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
// We assume that no camera will have more than one projection component,
|
||||
// so these systems will run independently of one another.
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(update_frusta::<PerspectiveProjection>)
|
||||
.ambiguous_with(update_frusta::<Projection>),
|
||||
update_frusta::<PerspectiveProjection>
|
||||
.in_set(UpdatePerspectiveFrusta)
|
||||
.after(camera_system::<PerspectiveProjection>)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
// We assume that no camera will have more than one projection component,
|
||||
// so these systems will run independently of one another.
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(update_frusta::<Projection>),
|
||||
update_frusta::<Projection>
|
||||
.in_set(UpdateProjectionFrusta)
|
||||
.after(camera_system::<Projection>)
|
||||
.after(TransformSystem::TransformPropagate),
|
||||
visibility_propagate_system.in_set(VisibilityPropagate),
|
||||
check_visibility
|
||||
.in_set(CheckVisibility)
|
||||
.after(CalculateBoundsFlush)
|
||||
.after(UpdateOrthographicFrusta)
|
||||
.after(UpdatePerspectiveFrusta)
|
||||
.after(UpdateProjectionFrusta)
|
||||
.after(VisibilityPropagate)
|
||||
.after(TransformSystem::TransformPropagate),
|
||||
));
|
||||
.configure_set(PostUpdate, CalculateBoundsFlush.after(CalculateBounds))
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
(
|
||||
calculate_bounds.in_set(CalculateBounds),
|
||||
update_frusta::<OrthographicProjection>
|
||||
.in_set(UpdateOrthographicFrusta)
|
||||
.after(camera_system::<OrthographicProjection>)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
// We assume that no camera will have more than one projection component,
|
||||
// so these systems will run independently of one another.
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(update_frusta::<PerspectiveProjection>)
|
||||
.ambiguous_with(update_frusta::<Projection>),
|
||||
update_frusta::<PerspectiveProjection>
|
||||
.in_set(UpdatePerspectiveFrusta)
|
||||
.after(camera_system::<PerspectiveProjection>)
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
// We assume that no camera will have more than one projection component,
|
||||
// so these systems will run independently of one another.
|
||||
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.
|
||||
.ambiguous_with(update_frusta::<Projection>),
|
||||
update_frusta::<Projection>
|
||||
.in_set(UpdateProjectionFrusta)
|
||||
.after(camera_system::<Projection>)
|
||||
.after(TransformSystem::TransformPropagate),
|
||||
visibility_propagate_system.in_set(VisibilityPropagate),
|
||||
check_visibility
|
||||
.in_set(CheckVisibility)
|
||||
.after(CalculateBoundsFlush)
|
||||
.after(UpdateOrthographicFrusta)
|
||||
.after(UpdatePerspectiveFrusta)
|
||||
.after(UpdateProjectionFrusta)
|
||||
.after(VisibilityPropagate)
|
||||
.after(TransformSystem::TransformPropagate),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -457,7 +454,7 @@ mod test {
|
|||
#[test]
|
||||
fn visibility_propagation() {
|
||||
let mut app = App::new();
|
||||
app.add_system(visibility_propagate_system);
|
||||
app.add_systems(Update, visibility_propagate_system);
|
||||
|
||||
let root1 = app
|
||||
.world
|
||||
|
@ -576,7 +573,7 @@ mod test {
|
|||
#[test]
|
||||
fn visibility_propagation_unconditional_visible() {
|
||||
let mut app = App::new();
|
||||
app.add_system(visibility_propagate_system);
|
||||
app.add_systems(Update, visibility_propagate_system);
|
||||
|
||||
let root1 = app
|
||||
.world
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{
|
||||
render_resource::TextureView,
|
||||
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_utils::{tracing::debug, HashMap, HashSet};
|
||||
use bevy_window::{
|
||||
|
@ -32,9 +32,9 @@ impl Plugin for WindowRenderPlugin {
|
|||
.init_resource::<ExtractedWindows>()
|
||||
.init_resource::<WindowSurfaces>()
|
||||
.init_non_send_resource::<NonSendMarker>()
|
||||
.add_system(extract_windows.in_schedule(ExtractSchedule))
|
||||
.configure_set(WindowSystem::Prepare.in_set(RenderSet::Prepare))
|
||||
.add_system(prepare_windows.in_set(WindowSystem::Prepare));
|
||||
.add_systems(ExtractSchedule, extract_windows)
|
||||
.configure_set(Render, WindowSystem::Prepare.in_set(RenderSet::Prepare))
|
||||
.add_systems(Render, prepare_windows.in_set(WindowSystem::Prepare));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ pub mod prelude {
|
|||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_asset::AddAsset;
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ScenePlugin;
|
||||
|
@ -36,9 +35,9 @@ impl Plugin for ScenePlugin {
|
|||
.add_asset::<Scene>()
|
||||
.init_asset_loader::<SceneLoader>()
|
||||
.init_resource::<SceneSpawner>()
|
||||
.add_system(scene_spawner_system)
|
||||
.add_systems(Update, 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::{
|
||||
render_phase::AddRenderCommand,
|
||||
render_resource::{Shader, SpecializedRenderPipelines},
|
||||
ExtractSchedule, RenderApp, RenderSet,
|
||||
ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -71,13 +71,14 @@ impl Plugin for SpritePlugin {
|
|||
.init_resource::<SpriteAssetEvents>()
|
||||
.add_render_command::<Transparent2d, DrawSprite>()
|
||||
.add_systems(
|
||||
ExtractSchedule,
|
||||
(
|
||||
extract_sprites.in_set(SpriteSystem::ExtractSprites),
|
||||
extract_sprite_events,
|
||||
)
|
||||
.in_schedule(ExtractSchedule),
|
||||
),
|
||||
)
|
||||
.add_system(
|
||||
.add_systems(
|
||||
Render,
|
||||
queue_sprites
|
||||
.in_set(RenderSet::Queue)
|
||||
.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_core_pipeline::{
|
||||
core_2d::Transparent2d,
|
||||
|
@ -32,7 +32,7 @@ use bevy_render::{
|
|||
renderer::RenderDevice,
|
||||
texture::FallbackImage,
|
||||
view::{ComputedVisibility, ExtractedView, Msaa, Visibility, VisibleEntities},
|
||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_transform::components::{GlobalTransform, Transform};
|
||||
use bevy_utils::{FloatOrd, HashMap, HashSet};
|
||||
|
@ -161,13 +161,16 @@ where
|
|||
.init_resource::<ExtractedMaterials2d<M>>()
|
||||
.init_resource::<RenderMaterials2d<M>>()
|
||||
.init_resource::<SpecializedMeshPipelines<Material2dPipeline<M>>>()
|
||||
.add_systems((
|
||||
extract_materials_2d::<M>.in_schedule(ExtractSchedule),
|
||||
prepare_materials_2d::<M>
|
||||
.in_set(RenderSet::Prepare)
|
||||
.after(PrepareAssetSet::PreAssetPrepare),
|
||||
queue_material2d_meshes::<M>.in_set(RenderSet::Queue),
|
||||
));
|
||||
.add_systems(ExtractSchedule, extract_materials_2d::<M>)
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_materials_2d::<M>
|
||||
.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_ecs::{
|
||||
|
@ -22,7 +22,7 @@ use bevy_render::{
|
|||
view::{
|
||||
ComputedVisibility, ExtractedView, ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms,
|
||||
},
|
||||
Extract, ExtractSchedule, RenderApp, RenderSet,
|
||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
|
||||
|
@ -103,11 +103,14 @@ impl Plugin for Mesh2dRenderPlugin {
|
|||
render_app
|
||||
.init_resource::<Mesh2dPipeline>()
|
||||
.init_resource::<SpecializedMeshPipelines<Mesh2dPipeline>>()
|
||||
.add_systems((
|
||||
extract_mesh2d.in_schedule(ExtractSchedule),
|
||||
queue_mesh2d_bind_group.in_set(RenderSet::Queue),
|
||||
queue_mesh2d_view_bind_groups.in_set(RenderSet::Queue),
|
||||
));
|
||||
.add_systems(ExtractSchedule, extract_mesh2d)
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
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::<FontAtlasWarning>()
|
||||
.insert_resource(TextPipeline::default())
|
||||
.add_system(
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
update_text2d_layout
|
||||
.in_base_set(CoreSet::PostUpdate)
|
||||
// Potential conflict: `Assets<Image>`
|
||||
// In practice, they run independently since `bevy_render::camera_update_system`
|
||||
// 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) {
|
||||
render_app.add_system(
|
||||
extract_text2d_sprite
|
||||
.after(SpriteSystem::ExtractSprites)
|
||||
.in_schedule(ExtractSchedule),
|
||||
render_app.add_systems(
|
||||
ExtractSchedule,
|
||||
extract_text2d_sprite.after(SpriteSystem::ExtractSprites),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,14 @@ use bevy_utils::Duration;
|
|||
/// If used for a fixed timestep system, use [`on_fixed_timer`] instead.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use bevy_app::{App, IntoSystemAppConfig, NoopPluginGroup as DefaultPlugins, PluginGroup};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfig;
|
||||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, Update};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
/// # use bevy_utils::Duration;
|
||||
/// # use bevy_time::common_conditions::on_timer;
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .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();
|
||||
/// }
|
||||
/// 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.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use bevy_app::{App, CoreSchedule, IntoSystemAppConfig, NoopPluginGroup as DefaultPlugins, PluginGroup};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfig;
|
||||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, FixedUpdate};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
/// # use bevy_utils::Duration;
|
||||
/// # use bevy_time::common_conditions::on_fixed_timer;
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_system(
|
||||
/// tick.in_schedule(CoreSchedule::FixedUpdate)
|
||||
/// .run_if(on_fixed_timer(Duration::from_secs(1))),
|
||||
/// .add_systems(FixedUpdate,
|
||||
/// tick.run_if(on_fixed_timer(Duration::from_secs(1))),
|
||||
/// )
|
||||
/// .run();
|
||||
/// }
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
//! Tools to run systems at a regular interval.
|
||||
//! 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).
|
||||
//! This schedules is run in the [`CoreSet::FixedUpdate`](bevy_app::CoreSet::FixedUpdate) near the start of each frame,
|
||||
//! To run a system on a fixed timestep, add it to the [`FixedUpdate`] [`Schedule`](bevy_ecs::schedule::Schedule).
|
||||
//! This schedule is run in [`RunFixedUpdateLoop`](bevy_app::RunFixedUpdateLoop) near the start of each frame,
|
||||
//! via the [`run_fixed_update_schedule`] exclusive system.
|
||||
//!
|
||||
//! 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.
|
||||
|
||||
use crate::Time;
|
||||
use bevy_app::CoreSchedule;
|
||||
use bevy_app::FixedUpdate;
|
||||
use bevy_ecs::{system::Resource, world::World};
|
||||
use bevy_utils::Duration;
|
||||
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) {
|
||||
// Tick the time
|
||||
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 fixed_time_run = fixed_time.expend().is_ok();
|
||||
if fixed_time_run {
|
||||
world.run_schedule(CoreSchedule::FixedUpdate);
|
||||
let _ = world.try_run_schedule(FixedUpdate);
|
||||
} else {
|
||||
check_again = false;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ mod stopwatch;
|
|||
mod time;
|
||||
mod timer;
|
||||
|
||||
use fixed_timestep::{run_fixed_update_schedule, FixedTime};
|
||||
use fixed_timestep::FixedTime;
|
||||
pub use stopwatch::*;
|
||||
pub use time::*;
|
||||
pub use timer::*;
|
||||
|
@ -21,9 +21,11 @@ pub mod prelude {
|
|||
pub use crate::{fixed_timestep::FixedTime, Time, Timer, TimerMode};
|
||||
}
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_app::{prelude::*, RunFixedUpdateLoop};
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
use crate::fixed_timestep::run_fixed_update_schedule;
|
||||
|
||||
/// Adds time functionality to Apps.
|
||||
#[derive(Default)]
|
||||
pub struct TimePlugin;
|
||||
|
@ -41,9 +43,8 @@ impl Plugin for TimePlugin {
|
|||
.register_type::<Time>()
|
||||
.register_type::<Stopwatch>()
|
||||
.init_resource::<FixedTime>()
|
||||
.configure_set(TimeSystem.in_base_set(CoreSet::First))
|
||||
.add_system(time_system.in_set(TimeSystem))
|
||||
.add_system(run_fixed_update_schedule.in_base_set(CoreSet::FixedUpdate));
|
||||
.add_systems(First, time_system.in_set(TimeSystem))
|
||||
.add_systems(RunFixedUpdateLoop, run_fixed_update_schedule);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ impl Time {
|
|||
/// world.insert_resource(Health { health_value: 0.2 });
|
||||
///
|
||||
/// let mut schedule = Schedule::new();
|
||||
/// schedule.add_system(health_system);
|
||||
/// schedule.add_systems(health_system);
|
||||
///
|
||||
/// // Simulate that 30 ms have passed
|
||||
/// 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
|
||||
/// [`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
|
||||
/// before the [`GlobalTransform`] is updated.
|
||||
///
|
||||
|
|
|
@ -23,7 +23,7 @@ use std::ops::Mul;
|
|||
/// [`GlobalTransform`] is updated from [`Transform`] by systems in the system set
|
||||
/// [`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
|
||||
/// 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
|
||||
/// [`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
|
||||
/// before the [`GlobalTransform`] is updated.
|
||||
#[derive(Bundle, Clone, Copy, Debug, Default)]
|
||||
|
@ -61,7 +61,7 @@ impl TransformBundle {
|
|||
/// Creates a new [`TransformBundle`] from a [`Transform`].
|
||||
///
|
||||
/// This initializes [`GlobalTransform`] as identity, to be updated later by the
|
||||
/// [`CoreSet::PostUpdate`](crate::CoreSet::PostUpdate) stage.
|
||||
/// [`PostUpdate`](bevy_app::PostUpdate) stage.
|
||||
#[inline]
|
||||
pub const fn from_transform(transform: Transform) -> Self {
|
||||
TransformBundle {
|
||||
|
@ -98,28 +98,35 @@ impl Plugin for TransformPlugin {
|
|||
app.register_type::<Transform>()
|
||||
.register_type::<GlobalTransform>()
|
||||
.add_plugin(ValidParentCheckPlugin::<GlobalTransform>::default())
|
||||
.configure_set(
|
||||
PostStartup,
|
||||
PropagateTransformsSet.in_set(TransformSystem::TransformPropagate),
|
||||
)
|
||||
// add transform systems to startup so the first update is "correct"
|
||||
.configure_set(TransformSystem::TransformPropagate.in_base_set(CoreSet::PostUpdate))
|
||||
.configure_set(PropagateTransformsSet.in_set(TransformSystem::TransformPropagate))
|
||||
.edit_schedule(CoreSchedule::Startup, |schedule| {
|
||||
schedule.configure_set(
|
||||
TransformSystem::TransformPropagate.in_base_set(StartupSet::PostStartup),
|
||||
);
|
||||
})
|
||||
.add_startup_systems((
|
||||
sync_simple_transforms
|
||||
.in_set(TransformSystem::TransformPropagate)
|
||||
// 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
|
||||
.ambiguous_with(PropagateTransformsSet),
|
||||
propagate_transforms.in_set(PropagateTransformsSet),
|
||||
))
|
||||
.add_systems((
|
||||
sync_simple_transforms
|
||||
.in_set(TransformSystem::TransformPropagate)
|
||||
.ambiguous_with(PropagateTransformsSet),
|
||||
propagate_transforms.in_set(PropagateTransformsSet),
|
||||
));
|
||||
.add_systems(
|
||||
PostStartup,
|
||||
(
|
||||
sync_simple_transforms
|
||||
.in_set(TransformSystem::TransformPropagate)
|
||||
// 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
|
||||
.ambiguous_with(PropagateTransformsSet),
|
||||
propagate_transforms.in_set(PropagateTransformsSet),
|
||||
),
|
||||
)
|
||||
.configure_set(
|
||||
PostUpdate,
|
||||
PropagateTransformsSet.in_set(TransformSystem::TransformPropagate),
|
||||
)
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
(
|
||||
sync_simple_transforms
|
||||
.in_set(TransformSystem::TransformPropagate)
|
||||
.ambiguous_with(PropagateTransformsSet),
|
||||
propagate_transforms.in_set(PropagateTransformsSet),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,7 +325,7 @@ mod test {
|
|||
let mut app = App::new();
|
||||
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);
|
||||
|
||||
|
@ -371,7 +371,7 @@ mod test {
|
|||
let mut temp = World::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) {
|
||||
let mut grandchild = Entity::from_raw(0);
|
||||
|
|
|
@ -1,25 +1,22 @@
|
|||
use crate::{
|
||||
prelude::{Button, Label},
|
||||
Node, UiImage,
|
||||
};
|
||||
use bevy_a11y::{
|
||||
accesskit::{NodeBuilder, Rect, Role},
|
||||
AccessibilityNode,
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
|
||||
use bevy_app::{App, Plugin, Update};
|
||||
use bevy_ecs::{
|
||||
prelude::Entity,
|
||||
query::{Changed, Or, Without},
|
||||
system::{Commands, Query},
|
||||
};
|
||||
use bevy_hierarchy::Children;
|
||||
|
||||
use bevy_render::prelude::Camera;
|
||||
use bevy_text::Text;
|
||||
use bevy_transform::prelude::GlobalTransform;
|
||||
|
||||
use crate::{
|
||||
prelude::{Button, Label},
|
||||
Node, UiImage,
|
||||
};
|
||||
|
||||
fn calc_name(texts: &Query<&Text>, children: &Children) -> Option<Box<str>> {
|
||||
let mut name = None;
|
||||
for child in children.iter() {
|
||||
|
@ -149,6 +146,9 @@ pub(crate) struct AccessibilityPlugin;
|
|||
|
||||
impl Plugin for AccessibilityPlugin {
|
||||
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::<widget::Button>()
|
||||
.register_type::<widget::Label>()
|
||||
.configure_set(UiSystem::Focus.in_base_set(CoreSet::PreUpdate))
|
||||
.configure_set(UiSystem::Flex.in_base_set(CoreSet::PostUpdate))
|
||||
.configure_set(UiSystem::Stack.in_base_set(CoreSet::PostUpdate))
|
||||
.add_system(ui_focus_system.in_set(UiSystem::Focus).after(InputSystem));
|
||||
.add_systems(
|
||||
PreUpdate,
|
||||
ui_focus_system.in_set(UiSystem::Focus).after(InputSystem),
|
||||
);
|
||||
// add these systems to front because these must run before transform update systems
|
||||
#[cfg(feature = "bevy_text")]
|
||||
app.add_system(
|
||||
app.add_systems(
|
||||
PostUpdate,
|
||||
widget::text_system
|
||||
.in_base_set(CoreSet::PostUpdate)
|
||||
.before(UiSystem::Flex)
|
||||
// Potential conflict: `Assets<Image>`
|
||||
// In practice, they run independently since `bevy_render::camera_update_system`
|
||||
|
@ -126,10 +126,8 @@ impl Plugin for UiPlugin {
|
|||
);
|
||||
#[cfg(feature = "bevy_text")]
|
||||
app.add_plugin(accessibility::AccessibilityPlugin);
|
||||
app.add_system({
|
||||
let system = widget::update_image_calculated_size_system
|
||||
.in_base_set(CoreSet::PostUpdate)
|
||||
.before(UiSystem::Flex);
|
||||
app.add_systems(PostUpdate, {
|
||||
let system = widget::update_image_calculated_size_system.before(UiSystem::Flex);
|
||||
// Potential conflicts: `Assets<Image>`
|
||||
// They run independently since `widget::image_node_system` will only ever observe
|
||||
// its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout`
|
||||
|
@ -141,15 +139,16 @@ impl Plugin for UiPlugin {
|
|||
|
||||
system
|
||||
})
|
||||
.add_systems((
|
||||
flex_node_system
|
||||
.in_set(UiSystem::Flex)
|
||||
.before(TransformSystem::TransformPropagate),
|
||||
ui_stack_system.in_set(UiSystem::Stack),
|
||||
update_clipping_system
|
||||
.after(TransformSystem::TransformPropagate)
|
||||
.in_base_set(CoreSet::PostUpdate),
|
||||
));
|
||||
.add_systems(
|
||||
PostUpdate,
|
||||
(
|
||||
flex_node_system
|
||||
.in_set(UiSystem::Flex)
|
||||
.before(TransformSystem::TransformPropagate),
|
||||
ui_stack_system.in_set(UiSystem::Stack),
|
||||
update_clipping_system.after(TransformSystem::TransformPropagate),
|
||||
),
|
||||
);
|
||||
|
||||
crate::render::build_ui_render(app);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ mod pipeline;
|
|||
mod render_pass;
|
||||
|
||||
use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d};
|
||||
use bevy_render::ExtractSchedule;
|
||||
use bevy_render::{ExtractSchedule, Render};
|
||||
#[cfg(feature = "bevy_text")]
|
||||
use bevy_window::{PrimaryWindow, Window};
|
||||
pub use pipeline::*;
|
||||
|
@ -77,20 +77,23 @@ pub fn build_ui_render(app: &mut App) {
|
|||
.init_resource::<DrawFunctions<TransparentUi>>()
|
||||
.add_render_command::<TransparentUi, DrawUi>()
|
||||
.add_systems(
|
||||
ExtractSchedule,
|
||||
(
|
||||
extract_default_ui_camera_view::<Camera2d>,
|
||||
extract_default_ui_camera_view::<Camera3d>,
|
||||
extract_uinodes.in_set(RenderUiSystem::ExtractNode),
|
||||
#[cfg(feature = "bevy_text")]
|
||||
extract_text_uinodes.after(RenderUiSystem::ExtractNode),
|
||||
)
|
||||
.in_schedule(ExtractSchedule),
|
||||
),
|
||||
)
|
||||
.add_systems((
|
||||
prepare_uinodes.in_set(RenderSet::Prepare),
|
||||
queue_uinodes.in_set(RenderSet::Queue),
|
||||
sort_phase_system::<TransparentUi>.in_set(RenderSet::PhaseSort),
|
||||
));
|
||||
.add_systems(
|
||||
Render,
|
||||
(
|
||||
prepare_uinodes.in_set(RenderSet::Prepare),
|
||||
queue_uinodes.in_set(RenderSet::Queue),
|
||||
sort_phase_system::<TransparentUi>.in_set(RenderSet::PhaseSort),
|
||||
),
|
||||
);
|
||||
|
||||
// Render graph
|
||||
let ui_graph_2d = get_ui_graph(render_app);
|
||||
|
|
|
@ -196,7 +196,7 @@ mod tests {
|
|||
queue.apply(&mut world);
|
||||
|
||||
let mut schedule = Schedule::default();
|
||||
schedule.add_system(ui_stack_system);
|
||||
schedule.add_systems(ui_stack_system);
|
||||
schedule.run(&mut world);
|
||||
|
||||
let mut query = world.query::<&Label>();
|
||||
|
|
|
@ -22,7 +22,6 @@ pub mod prelude {
|
|||
}
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
impl Default for WindowPlugin {
|
||||
|
@ -53,14 +52,14 @@ pub struct WindowPlugin {
|
|||
/// surprise your users. It is recommended to leave this setting to
|
||||
/// either [`ExitCondition::OnAllClosed`] or [`ExitCondition::OnPrimaryClosed`].
|
||||
///
|
||||
/// [`ExitCondition::OnAllClosed`] will add [`exit_on_all_closed`] to [`CoreSet::Update`].
|
||||
/// [`ExitCondition::OnPrimaryClosed`] will add [`exit_on_primary_closed`] to [`CoreSet::Update`].
|
||||
/// [`ExitCondition::OnAllClosed`] will add [`exit_on_all_closed`] to [`Update`].
|
||||
/// [`ExitCondition::OnPrimaryClosed`] will add [`exit_on_primary_closed`] to [`Update`].
|
||||
pub exit_condition: ExitCondition,
|
||||
|
||||
/// Whether to close windows when they are requested to be closed (i.e.
|
||||
/// 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.
|
||||
/// This may surprise your users. It is recommended to leave this setting as `true`.
|
||||
pub close_when_requested: bool,
|
||||
|
@ -93,17 +92,17 @@ impl Plugin for WindowPlugin {
|
|||
|
||||
match self.exit_condition {
|
||||
ExitCondition::OnPrimaryClosed => {
|
||||
app.add_system(exit_on_primary_closed.in_base_set(CoreSet::PostUpdate));
|
||||
app.add_systems(PostUpdate, exit_on_primary_closed);
|
||||
}
|
||||
ExitCondition::OnAllClosed => {
|
||||
app.add_system(exit_on_all_closed.in_base_set(CoreSet::PostUpdate));
|
||||
app.add_systems(PostUpdate, exit_on_all_closed);
|
||||
}
|
||||
ExitCondition::DontExit => {}
|
||||
}
|
||||
|
||||
if self.close_when_requested {
|
||||
// Need to run before `exit_on_*` systems
|
||||
app.add_system(close_when_requested);
|
||||
app.add_systems(Update, close_when_requested);
|
||||
}
|
||||
|
||||
// Register event types
|
||||
|
@ -143,11 +142,11 @@ impl Plugin for WindowPlugin {
|
|||
pub enum ExitCondition {
|
||||
/// 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,
|
||||
/// 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,
|
||||
/// Keep application running headless even after closing all windows
|
||||
///
|
||||
|
|
|
@ -8,7 +8,7 @@ use bevy_a11y::{
|
|||
accesskit::{ActionHandler, ActionRequest, NodeBuilder, NodeClassSet, Role, TreeUpdate},
|
||||
AccessKitEntityExt, AccessibilityNode, AccessibilityRequested, Focus,
|
||||
};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_app::{App, Plugin, Update};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
prelude::{DetectChanges, Entity, EventReader, EventWriter},
|
||||
|
@ -163,11 +163,14 @@ impl Plugin for AccessibilityPlugin {
|
|||
app.init_non_send_resource::<AccessKitAdapters>()
|
||||
.init_resource::<WinitActionHandlers>()
|
||||
.add_event::<ActionRequest>()
|
||||
.add_systems((
|
||||
handle_window_focus,
|
||||
window_closed,
|
||||
poll_receivers,
|
||||
update_accessibility_nodes,
|
||||
));
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
handle_window_focus,
|
||||
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_windows::*;
|
||||
|
||||
use bevy_app::{App, AppExit, CoreSet, Plugin};
|
||||
use bevy_app::{App, AppExit, Last, Plugin};
|
||||
use bevy_ecs::event::{Events, ManualEventReader};
|
||||
use bevy_ecs::prelude::*;
|
||||
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,
|
||||
// and so doesn't care about ordering relative to changed_window
|
||||
.add_systems(
|
||||
Last,
|
||||
(
|
||||
changed_window.ambiguous_with(exit_on_all_closed),
|
||||
// Update the state of the window before attempting to despawn to ensure consistent event ordering
|
||||
despawn_window.after(changed_window),
|
||||
)
|
||||
.in_base_set(CoreSet::Last),
|
||||
),
|
||||
);
|
||||
|
||||
app.add_plugin(AccessibilityPlugin);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::WinitWindows;
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_app::{App, Plugin, Update};
|
||||
use bevy_ecs::prelude::*;
|
||||
use crossbeam_channel::{Receiver, Sender};
|
||||
use wasm_bindgen::JsCast;
|
||||
|
@ -10,7 +10,7 @@ pub(crate) struct CanvasParentResizePlugin;
|
|||
impl Plugin for CanvasParentResizePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
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() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_system(move_enemies_to_player)
|
||||
.add_systems(Update, move_enemies_to_player)
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
@ -55,7 +55,7 @@ fn move_enemies_to_player(
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_system(move_enemies_to_player)
|
||||
.add_systems(Update, move_enemies_to_player)
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
@ -85,7 +85,7 @@ fn move_enemies_to_player(
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_system(move_enemies_to_player)
|
||||
.add_systems(Update, move_enemies_to_player)
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
|
|
@ -17,7 +17,7 @@ fn update_materials(
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_system(update_materials)
|
||||
.add_systems(Update, update_materials)
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
@ -38,7 +38,7 @@ fn update_materials(
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_system(update_materials)
|
||||
.add_systems(Update, update_materials)
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
|
|
@ -10,9 +10,9 @@ use bevy::prelude::*;
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_startup_system(setup)
|
||||
.add_system(despawning)
|
||||
.add_system(use_entity.after(despawning))
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, despawning)
|
||||
.add_systems(Update, use_entity.after(despawning))
|
||||
.run();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ fn setup_cube(
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_startup_system(setup_cube)
|
||||
.add_systems(Startup, setup_cube)
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
@ -97,7 +97,7 @@ fn setup_cube(
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_startup_system(setup_cube)
|
||||
.add_systems(Startup, setup_cube)
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
|
|
@ -5,7 +5,7 @@ use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_startup_system(setup)
|
||||
.add_systems(Startup, setup)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ fn main() {
|
|||
App::new()
|
||||
.insert_resource(ClearColor(Color::DARK_GRAY))
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems((setup.on_startup(), update_bloom_settings))
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, update_bloom_settings)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
|
|||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_startup_system(setup)
|
||||
.add_systems(Startup, setup)
|
||||
.run();
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue