Struct bevy::ecs::prelude::Schedule

pub struct Schedule { /* private fields */ }
Expand description

A collection of systems, and the metadata and executor needed to run them in a certain order under certain conditions.

§Example

Here is an example of a Schedule running a “Hello world” system:

fn hello_world() { println!("Hello world!") }

fn main() {
    let mut world = World::new();
    let mut schedule = Schedule::default();
    schedule.add_systems(hello_world);

    schedule.run(&mut world);
}

A schedule can also run several systems in an ordered way:

fn system_one() { println!("System 1 works!") }
fn system_two() { println!("System 2 works!") }
fn system_three() { println!("System 3 works!") }
    
fn main() {
    let mut world = World::new();
    let mut schedule = Schedule::default();
    schedule.add_systems((
        system_two,
        system_one.before(system_two),
        system_three.after(system_two),
    ));

    schedule.run(&mut world);
}

Implementations§

§

impl Schedule

pub fn new(label: impl ScheduleLabel) -> Schedule

Constructs an empty Schedule.

Examples found in repository?
examples/ecs/custom_schedule.rs (line 20)
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
fn main() {
    let mut app = App::new();

    // Create a new [`Schedule`]. For demonstration purposes, we configure it to use a single threaded executor so that
    // systems in this schedule are never run in parallel. However, this is not a requirement for custom schedules in
    // general.
    let mut custom_update_schedule = Schedule::new(SingleThreadedUpdate);
    custom_update_schedule.set_executor_kind(ExecutorKind::SingleThreaded);

    // Adding the schedule to the app does not automatically run the schedule. This merely registers the schedule so
    // that systems can look it up using the `Schedules` resource.
    app.add_schedule(custom_update_schedule);

    // Bevy `App`s have a `main_schedule_label` field that configures which schedule is run by the App's `runner`.
    // By default, this is `Main`. The `Main` schedule is responsible for running Bevy's main schedules such as
    // `Update`, `Startup` or `Last`.
    //
    // We can configure the `Main` schedule to run our custom update schedule relative to the existing ones by modifying
    // the `MainScheduleOrder` resource.
    //
    // Note that we modify `MainScheduleOrder` directly in `main` and not in a startup system. The reason for this is
    // that the `MainScheduleOrder` cannot be modified from systems that are run as part of the `Main` schedule.
    let mut main_schedule_order = app.world_mut().resource_mut::<MainScheduleOrder>();
    main_schedule_order.insert_after(Update, SingleThreadedUpdate);

    // Adding a custom startup schedule works similarly, but needs to use `insert_startup_after`
    // instead of `insert_after`.
    app.add_schedule(Schedule::new(CustomStartup));

    let mut main_schedule_order = app.world_mut().resource_mut::<MainScheduleOrder>();
    main_schedule_order.insert_startup_after(PreStartup, CustomStartup);

    app.add_systems(SingleThreadedUpdate, single_threaded_update_system)
        .add_systems(CustomStartup, custom_startup_system)
        .add_systems(PreStartup, pre_startup_system)
        .add_systems(Startup, startup_system)
        .add_systems(First, first_system)
        .add_systems(Update, update_system)
        .add_systems(Last, last_system)
        .run();
}

pub fn label(&self) -> Interned<dyn ScheduleLabel>

Get the InternedScheduleLabel for this Schedule.

pub fn add_systems<M>( &mut self, systems: impl IntoSystemConfigs<M> ) -> &mut Schedule

Add a collection of systems to the schedule.

pub fn ignore_ambiguity<M1, M2, S1, S2>( &mut self, a: S1, b: S2 ) -> &mut Schedule
where S1: IntoSystemSet<M1>, S2: IntoSystemSet<M2>,

Suppress warnings and errors that would result from systems in these sets having ambiguities (conflicting access but indeterminate order) with systems in set.

pub fn configure_sets( &mut self, sets: impl IntoSystemSetConfigs ) -> &mut Schedule

Configures a collection of system sets in this schedule, adding them if they does not exist.

pub fn set_build_settings( &mut self, settings: ScheduleBuildSettings ) -> &mut Schedule

Changes miscellaneous build settings.

Examples found in repository?
examples/ecs/nondeterministic_system_order.rs (lines 26-29)
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
fn main() {
    App::new()
        // We can modify the reporting strategy for system execution order ambiguities on a per-schedule basis.
        // You must do this for each schedule you want to inspect; child schedules executed within an inspected
        // schedule do not inherit this modification.
        .edit_schedule(Update, |schedule| {
            schedule.set_build_settings(ScheduleBuildSettings {
                ambiguity_detection: LogLevel::Warn,
                ..default()
            });
        })
        .init_resource::<A>()
        .init_resource::<B>()
        .add_systems(
            Update,
            (
                // This pair of systems has an ambiguous order,
                // as their data access conflicts, and there's no order between them.
                reads_a,
                writes_a,
                // This pair of systems has conflicting data access,
                // but it's resolved with an explicit ordering:
                // the .after relationship here means that we will always double after adding.
                adds_one_to_b,
                doubles_b.after(adds_one_to_b),
                // This system isn't ambiguous with adds_one_to_b,
                // due to the transitive ordering created by our constraints:
                // if A is before B is before C, then A must be before C as well.
                reads_b.after(doubles_b),
                // This system will conflict with all of our writing systems
                // but we've silenced its ambiguity with adds_one_to_b.
                // This should only be done in the case of clear false positives:
                // leave a comment in your code justifying the decision!
                reads_a_and_b.ambiguous_with(adds_one_to_b),
            ),
        )
        // Be mindful, internal ambiguities are reported too!
        // If there are any ambiguities due solely to DefaultPlugins,
        // or between DefaultPlugins and any of your third party plugins,
        // please file a bug with the repo responsible!
        // Only *you* can prevent nondeterministic bugs due to greedy parallelism.
        .add_plugins(DefaultPlugins)
        .run();
}

pub fn get_build_settings(&self) -> ScheduleBuildSettings

Returns the schedule’s current ScheduleBuildSettings.

pub fn get_executor_kind(&self) -> ExecutorKind

Returns the schedule’s current execution strategy.

pub fn set_executor_kind(&mut self, executor: ExecutorKind) -> &mut Schedule

Sets the schedule’s execution strategy.

Examples found in repository?
examples/ecs/custom_schedule.rs (line 21)
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
fn main() {
    let mut app = App::new();

    // Create a new [`Schedule`]. For demonstration purposes, we configure it to use a single threaded executor so that
    // systems in this schedule are never run in parallel. However, this is not a requirement for custom schedules in
    // general.
    let mut custom_update_schedule = Schedule::new(SingleThreadedUpdate);
    custom_update_schedule.set_executor_kind(ExecutorKind::SingleThreaded);

    // Adding the schedule to the app does not automatically run the schedule. This merely registers the schedule so
    // that systems can look it up using the `Schedules` resource.
    app.add_schedule(custom_update_schedule);

    // Bevy `App`s have a `main_schedule_label` field that configures which schedule is run by the App's `runner`.
    // By default, this is `Main`. The `Main` schedule is responsible for running Bevy's main schedules such as
    // `Update`, `Startup` or `Last`.
    //
    // We can configure the `Main` schedule to run our custom update schedule relative to the existing ones by modifying
    // the `MainScheduleOrder` resource.
    //
    // Note that we modify `MainScheduleOrder` directly in `main` and not in a startup system. The reason for this is
    // that the `MainScheduleOrder` cannot be modified from systems that are run as part of the `Main` schedule.
    let mut main_schedule_order = app.world_mut().resource_mut::<MainScheduleOrder>();
    main_schedule_order.insert_after(Update, SingleThreadedUpdate);

    // Adding a custom startup schedule works similarly, but needs to use `insert_startup_after`
    // instead of `insert_after`.
    app.add_schedule(Schedule::new(CustomStartup));

    let mut main_schedule_order = app.world_mut().resource_mut::<MainScheduleOrder>();
    main_schedule_order.insert_startup_after(PreStartup, CustomStartup);

    app.add_systems(SingleThreadedUpdate, single_threaded_update_system)
        .add_systems(CustomStartup, custom_startup_system)
        .add_systems(PreStartup, pre_startup_system)
        .add_systems(Startup, startup_system)
        .add_systems(First, first_system)
        .add_systems(Update, update_system)
        .add_systems(Last, last_system)
        .run();
}

pub fn set_apply_final_deferred( &mut self, apply_final_deferred: bool ) -> &mut Schedule

Set whether the schedule applies deferred system buffers on final time or not. This is a catch-all in case a system uses commands but was not explicitly ordered before an instance of apply_deferred. By default this setting is true, but may be disabled if needed.

pub fn run(&mut self, world: &mut World)

Runs all systems in this schedule on the world, using its current execution strategy.

pub fn initialize( &mut self, world: &mut World ) -> Result<(), ScheduleBuildError>

Initializes any newly-added systems and conditions, rebuilds the executable schedule, and re-initializes the executor.

Moves all systems and run conditions out of the ScheduleGraph.

pub fn graph(&self) -> &ScheduleGraph

Returns the ScheduleGraph.

pub fn graph_mut(&mut self) -> &mut ScheduleGraph

Returns a mutable reference to the ScheduleGraph.

pub fn apply_deferred(&mut self, world: &mut World)

Directly applies any accumulated Deferred system parameters (like Commands) to the world.

Like always, deferred system parameters are applied in the “topological sort order” of the schedule graph. As a result, buffers from one system are only guaranteed to be applied before those of other systems if there is an explicit system ordering between the two systems.

This is used in rendering to extract data from the main world, storing the data in system buffers, before applying their buffers in a different world.

pub fn systems( &self ) -> Result<impl Iterator<Item = (NodeId, &Box<dyn System<Out = (), In = ()>>)>, ScheduleNotInitialized>

Returns an iterator over all systems in this schedule.

Note: this method will return ScheduleNotInitialized if the schedule has never been initialized or run.

Examples found in repository?
examples/games/stepping.rs (line 130)
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
fn build_ui(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    schedules: Res<Schedules>,
    mut stepping: ResMut<Stepping>,
    mut state: ResMut<State>,
) {
    let mut text_sections = Vec::new();
    let mut always_run = Vec::new();

    let Ok(schedule_order) = stepping.schedules() else {
        return;
    };

    // go through the stepping schedules and construct a list of systems for
    // each label
    for label in schedule_order {
        let schedule = schedules.get(*label).unwrap();
        text_sections.push(TextSection::new(
            format!("{:?}\n", label),
            TextStyle {
                font: asset_server.load(FONT_BOLD),
                font_size: FONT_SIZE,
                color: FONT_COLOR,
            },
        ));

        // grab the list of systems in the schedule, in the order the
        // single-threaded executor would run them.
        let Ok(systems) = schedule.systems() else {
            return;
        };

        for (node_id, system) in systems {
            // skip bevy default systems; we don't want to step those
            if system.name().starts_with("bevy") {
                always_run.push((*label, node_id));
                continue;
            }

            // Add an entry to our systems list so we can find where to draw
            // the cursor when the stepping cursor is at this system
            state.systems.push((*label, node_id, text_sections.len()));

            // Add a text section for displaying the cursor for this system
            text_sections.push(TextSection::new(
                "   ",
                TextStyle {
                    font: asset_server.load(FONT_MEDIUM),
                    font_size: FONT_SIZE,
                    color: FONT_COLOR,
                },
            ));

            // add the name of the system to the ui
            text_sections.push(TextSection::new(
                format!("{}\n", system.name()),
                TextStyle {
                    font: asset_server.load(FONT_MEDIUM),
                    font_size: FONT_SIZE,
                    color: FONT_COLOR,
                },
            ));
        }
    }

    for (label, node) in always_run.drain(..) {
        stepping.always_run_node(label, node);
    }

    commands.spawn((
        SteppingUi,
        TextBundle {
            text: Text::from_sections(text_sections),
            style: Style {
                position_type: PositionType::Absolute,
                top: state.ui_top,
                left: state.ui_left,
                padding: UiRect::all(Val::Px(10.0)),
                ..default()
            },
            background_color: BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.33)),
            visibility: Visibility::Hidden,
            ..default()
        },
    ));
}

pub fn systems_len(&self) -> usize

Returns the number of systems in this schedule.

Trait Implementations§

§

impl Default for Schedule

§

fn default() -> Schedule

Creates a schedule with a default label. Only use in situations where you don’t care about the ScheduleLabel. Inserting a default schedule into the world risks overwriting another schedule. For most situations you should use Schedule::new.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

§

impl<T> FromWorld for T
where T: Default,

§

fn from_world(_world: &mut World) -> T

Creates Self using data from the given World.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

§

fn into_sample(self) -> T

§

impl<T> NoneValue for T
where T: Default,

§

type NoneType = T

§

fn null_value() -> T

The none-equivalent value.
§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
source§

impl<T> Same for T

§

type Output = T

Should always be Self
§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

§

fn to_sample_(self) -> U

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
§

impl<T> ConditionalSend for T
where T: Send,

§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

§

impl<T> Settings for T
where T: 'static + Send + Sync,

§

impl<T> WasmNotSend for T
where T: Send,

§

impl<T> WasmNotSendSync for T
where T: WasmNotSend + WasmNotSync,

§

impl<T> WasmNotSync for T
where T: Sync,