Skip to content

Commit dcc0372

Browse files
committed
Base Sets (#7466)
# Objective NOTE: This depends on #7267 and should not be merged until #7267 is merged. If you are reviewing this before that is merged, I highly recommend viewing the Base Sets commit instead of trying to find my changes amongst those from #7267. "Default sets" as described by the [Stageless RFC](bevyengine/rfcs#45) have some [unfortunate consequences](#7365). ## Solution This adds "base sets" as a variant of `SystemSet`: A set is a "base set" if `SystemSet::is_base` returns `true`. Typically this will be opted-in to using the `SystemSet` derive: ```rust #[derive(SystemSet, Clone, Hash, Debug, PartialEq, Eq)] #[system_set(base)] enum MyBaseSet { A, B, } ``` **Base sets are exclusive**: a system can belong to at most one "base set". Adding a system to more than one will result in an error. When possible we fail immediately during system-config-time with a nice file + line number. For the more nested graph-ey cases, this will fail at the final schedule build. **Base sets cannot belong to other sets**: this is where the word "base" comes from Systems and Sets can only be added to base sets using `in_base_set`. Calling `in_set` with a base set will fail. As will calling `in_base_set` with a normal set. ```rust app.add_system(foo.in_base_set(MyBaseSet::A)) // X must be a normal set ... base sets cannot be added to base sets .configure_set(X.in_base_set(MyBaseSet::A)) ``` Base sets can still be configured like normal sets: ```rust app.add_system(MyBaseSet::B.after(MyBaseSet::Ap)) ``` The primary use case for base sets is enabling a "default base set": ```rust schedule.set_default_base_set(CoreSet::Update) // this will belong to CoreSet::Update by default .add_system(foo) // this will override the default base set with PostUpdate .add_system(bar.in_base_set(CoreSet::PostUpdate)) ``` This allows us to build apis that work by default in the standard Bevy style. This is a rough analog to the "default stage" model, but it use the new "stageless sets" model instead, with all of the ordering flexibility (including exclusive systems) that it provides. --- ## Changelog - Added "base sets" and ported CoreSet to use them. ## Migration Guide TODO
1 parent 206c7ce commit dcc0372

File tree

84 files changed

+916
-274
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+916
-274
lines changed

crates/bevy_animation/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ impl Plugin for AnimationPlugin {
552552
.register_type::<AnimationPlayer>()
553553
.add_system(
554554
animation_player
555-
.in_set(CoreSet::PostUpdate)
555+
.in_base_set(CoreSet::PostUpdate)
556556
.before(TransformSystem::TransformPropagate),
557557
);
558558
}

crates/bevy_app/src/app.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,14 +328,14 @@ impl App {
328328
apply_state_transition::<S>,
329329
)
330330
.chain()
331-
.in_set(CoreSet::StateTransitions),
331+
.in_base_set(CoreSet::StateTransitions),
332332
);
333333

334334
let main_schedule = self.get_schedule_mut(CoreSchedule::Main).unwrap();
335335
for variant in S::variants() {
336336
main_schedule.configure_set(
337337
OnUpdate(variant.clone())
338-
.in_set(CoreSet::StateTransitions)
338+
.in_base_set(CoreSet::StateTransitions)
339339
.run_if(state_equals(variant))
340340
.after(apply_state_transition::<S>),
341341
);
@@ -580,7 +580,7 @@ impl App {
580580
{
581581
if !self.world.contains_resource::<Events<T>>() {
582582
self.init_resource::<Events<T>>()
583-
.add_system(Events::<T>::update_system.in_set(CoreSet::First));
583+
.add_system(Events::<T>::update_system.in_base_set(CoreSet::First));
584584
}
585585
self
586586
}

crates/bevy_app/src/lib.rs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ pub mod prelude {
2929

3030
use bevy_ecs::{
3131
schedule_v3::{
32-
apply_system_buffers, IntoSystemConfig, IntoSystemSetConfig, Schedule, ScheduleLabel,
33-
SystemSet,
32+
apply_system_buffers, IntoSystemConfig, IntoSystemSetConfig, IntoSystemSetConfigs,
33+
Schedule, ScheduleLabel, SystemSet,
3434
},
3535
system::Local,
3636
world::World,
@@ -90,6 +90,7 @@ impl CoreSchedule {
9090
/// that runs immediately after the matching system set.
9191
/// These can be useful for ordering, but you almost never want to add your systems to these sets.
9292
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
93+
#[system_set(base)]
9394
pub enum CoreSet {
9495
/// Runs before all other members of this set.
9596
First,
@@ -129,20 +130,30 @@ impl CoreSet {
129130
let mut schedule = Schedule::new();
130131

131132
// Create "stage-like" structure using buffer flushes + ordering
132-
schedule.add_system(apply_system_buffers.in_set(FirstFlush));
133-
schedule.add_system(apply_system_buffers.in_set(PreUpdateFlush));
134-
schedule.add_system(apply_system_buffers.in_set(UpdateFlush));
135-
schedule.add_system(apply_system_buffers.in_set(PostUpdateFlush));
136-
schedule.add_system(apply_system_buffers.in_set(LastFlush));
137-
138-
schedule.configure_set(First.before(FirstFlush));
139-
schedule.configure_set(PreUpdate.after(FirstFlush).before(PreUpdateFlush));
140-
schedule.configure_set(StateTransitions.after(PreUpdateFlush).before(FixedUpdate));
141-
schedule.configure_set(FixedUpdate.after(StateTransitions).before(Update));
142-
schedule.configure_set(Update.after(FixedUpdate).before(UpdateFlush));
143-
schedule.configure_set(PostUpdate.after(UpdateFlush).before(PostUpdateFlush));
144-
schedule.configure_set(Last.after(PostUpdateFlush).before(LastFlush));
145-
133+
schedule
134+
.set_default_base_set(Update)
135+
.add_system(apply_system_buffers.in_base_set(FirstFlush))
136+
.add_system(apply_system_buffers.in_base_set(PreUpdateFlush))
137+
.add_system(apply_system_buffers.in_base_set(UpdateFlush))
138+
.add_system(apply_system_buffers.in_base_set(PostUpdateFlush))
139+
.add_system(apply_system_buffers.in_base_set(LastFlush))
140+
.configure_sets(
141+
(
142+
First,
143+
FirstFlush,
144+
PreUpdate,
145+
PreUpdateFlush,
146+
StateTransitions,
147+
FixedUpdate,
148+
Update,
149+
UpdateFlush,
150+
PostUpdate,
151+
PostUpdateFlush,
152+
Last,
153+
LastFlush,
154+
)
155+
.chain(),
156+
);
146157
schedule
147158
}
148159
}

crates/bevy_asset/src/asset_server.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ pub fn free_unused_assets_system(asset_server: Res<AssetServer>) {
644644
mod test {
645645
use super::*;
646646
use crate::{loader::LoadedAsset, update_asset_storage_system};
647-
use bevy_app::{App, CoreSet};
647+
use bevy_app::App;
648648
use bevy_ecs::prelude::*;
649649
use bevy_reflect::TypeUuid;
650650
use bevy_utils::BoxedFuture;
@@ -852,16 +852,8 @@ mod test {
852852
let mut app = App::new();
853853
app.insert_resource(assets);
854854
app.insert_resource(asset_server);
855-
app.add_system(
856-
free_unused_assets_system
857-
.in_set(FreeUnusedAssets)
858-
.in_set(CoreSet::Update),
859-
);
860-
app.add_system(
861-
update_asset_storage_system::<PngAsset>
862-
.after(FreeUnusedAssets)
863-
.in_set(CoreSet::Update),
864-
);
855+
app.add_system(free_unused_assets_system.in_set(FreeUnusedAssets));
856+
app.add_system(update_asset_storage_system::<PngAsset>.after(FreeUnusedAssets));
865857

866858
fn load_asset(path: AssetPath, world: &World) -> HandleUntyped {
867859
let asset_server = world.resource::<AssetServer>();

crates/bevy_asset/src/assets.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,8 @@ impl AddAsset for App {
331331
};
332332

333333
self.insert_resource(assets)
334-
.add_system(Assets::<T>::asset_event_system.in_set(AssetSet::AssetEvents))
335-
.add_system(update_asset_storage_system::<T>.in_set(AssetSet::LoadAssets))
334+
.add_system(Assets::<T>::asset_event_system.in_base_set(AssetSet::AssetEvents))
335+
.add_system(update_asset_storage_system::<T>.in_base_set(AssetSet::LoadAssets))
336336
.register_type::<Handle<T>>()
337337
.add_event::<AssetEvent<T>>()
338338
}

crates/bevy_asset/src/debug_asset_server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! Internal assets (e.g. shaders) are bundled directly into an application and can't be hot
44
//! reloaded using the conventional API.
5-
use bevy_app::{App, CoreSet, Plugin};
5+
use bevy_app::{App, Plugin};
66
use bevy_ecs::{prelude::*, system::SystemState};
77
use bevy_tasks::{IoTaskPool, TaskPoolBuilder};
88
use bevy_utils::HashMap;
@@ -75,7 +75,7 @@ impl Plugin for DebugAssetServerPlugin {
7575
watch_for_changes: true,
7676
});
7777
app.insert_non_send_resource(DebugAssetApp(debug_asset_app));
78-
app.add_system(run_debug_asset_app.in_set(CoreSet::Update));
78+
app.add_system(run_debug_asset_app);
7979
}
8080
}
8181

crates/bevy_asset/src/diagnostic/asset_count_diagnostics_plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl<T: Asset> Default for AssetCountDiagnosticsPlugin<T> {
1919
impl<T: Asset> Plugin for AssetCountDiagnosticsPlugin<T> {
2020
fn build(&self, app: &mut App) {
2121
app.add_startup_system(Self::setup_system.in_set(StartupSet::Startup))
22-
.add_system(Self::diagnostic_system.in_set(CoreSet::Update));
22+
.add_system(Self::diagnostic_system);
2323
}
2424
}
2525

crates/bevy_asset/src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use bevy_ecs::prelude::*;
5151

5252
/// [`SystemSet`]s for asset loading in an [`App`] schedule.
5353
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
54+
#[system_set(base)]
5455
pub enum AssetSet {
5556
/// Asset storages are updated.
5657
LoadAssets,
@@ -109,22 +110,20 @@ impl Plugin for AssetPlugin {
109110

110111
app.configure_set(
111112
AssetSet::LoadAssets
112-
.no_default_set()
113113
.before(CoreSet::PreUpdate)
114114
.after(CoreSet::First),
115115
)
116116
.configure_set(
117117
AssetSet::AssetEvents
118-
.no_default_set()
119118
.after(CoreSet::PostUpdate)
120119
.before(CoreSet::Last),
121120
)
122-
.add_system(asset_server::free_unused_assets_system.in_set(CoreSet::PreUpdate));
121+
.add_system(asset_server::free_unused_assets_system.in_base_set(CoreSet::PreUpdate));
123122

124123
#[cfg(all(
125124
feature = "filesystem_watcher",
126125
all(not(target_arch = "wasm32"), not(target_os = "android"))
127126
))]
128-
app.add_system(io::filesystem_watcher_system.in_set(AssetSet::LoadAssets));
127+
app.add_system(io::filesystem_watcher_system.in_base_set(AssetSet::LoadAssets));
129128
}
130129
}

crates/bevy_audio/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl Plugin for AudioPlugin {
5656
.add_asset::<AudioSource>()
5757
.add_asset::<AudioSink>()
5858
.init_resource::<Audio<AudioSource>>()
59-
.add_system(play_queued_audio_system::<AudioSource>.in_set(CoreSet::PostUpdate));
59+
.add_system(play_queued_audio_system::<AudioSource>.in_base_set(CoreSet::PostUpdate));
6060

6161
#[cfg(any(feature = "mp3", feature = "flac", feature = "wav", feature = "vorbis"))]
6262
app.init_asset_loader::<AudioLoader>();
@@ -71,6 +71,6 @@ impl AddAudioSource for App {
7171
self.add_asset::<T>()
7272
.init_resource::<Audio<T>>()
7373
.init_resource::<AudioOutput<T>>()
74-
.add_system(play_queued_audio_system::<T>.in_set(CoreSet::PostUpdate))
74+
.add_system(play_queued_audio_system::<T>.in_base_set(CoreSet::PostUpdate))
7575
}
7676
}

crates/bevy_core/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ impl Plugin for TaskPoolPlugin {
107107
self.task_pool_options.create_default_pools();
108108

109109
#[cfg(not(target_arch = "wasm32"))]
110-
app.add_system(tick_global_task_pools.in_set(bevy_app::CoreSet::Last));
110+
app.add_system(tick_global_task_pools.in_base_set(bevy_app::CoreSet::Last));
111111
}
112112
}
113113
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
@@ -142,7 +142,7 @@ pub struct FrameCountPlugin;
142142
impl Plugin for FrameCountPlugin {
143143
fn build(&self, app: &mut App) {
144144
app.init_resource::<FrameCount>();
145-
app.add_system(update_frame_count.in_set(CoreSet::Last));
145+
app.add_system(update_frame_count.in_base_set(CoreSet::Last));
146146
}
147147
}
148148

0 commit comments

Comments
 (0)