Skip to content

Unflushed commands before exclusive system when configured with *_ignore_deferred #17828

@urben1680

Description

@urben1680

Bevy version

I saw this behavior at around 0.14 I think but only now got around making a minimal reproducible example on main, or at least a fairly recent commit behind main.

What you did

I ran this code:

use bevy::prelude::*;

#[derive(Resource)]
struct InsertTest;

fn insert_system(mut commands: Commands) {
    commands.insert_resource(InsertTest);
}
fn assert_system(world: &mut World) {
    assert!(world.contains_resource::<InsertTest>())
}

fn main() {
    App::new()
        .add_systems(
            Update, 
            (insert_system, assert_system).chain_ignore_deferred()
        )
        .update();
}

What went wrong

assert_system is an exclusive system, therefore it is expected that the command in insert_system is flushed before it runs. The assertion should not fail but it does.

Additional information

I did some extensive testing and noticed that this bug occurs no matter how I do this configuration as long I make use of the _ignore_deferred variants. The following table lists these configurations and gives each a number because that matters for another observation I elaborate further down.

inserting config by asserting config by config test
system system after_ignore_deferred 1
system system before_ignore_deferred 2
system system chain_ignore_deferred 3
system set after_ignore_deferred 4
system set before_ignore_deferred 5
set system after_ignore_deferred 6
set system before_ignore_deferred 7
set set after_ignore_deferred 8
set set before_ignore_deferred 9
set set chain_ignore_deferred 10

For example the configuration...

(insert_system, assert_system).chain_ignore_deferred()

... is the third row in the table, where "inserting config by" with "system" means that the first element in the chain tuple is the system, and "asserting config by" with "system" means that the second element in the tuple is also the system itself.

"set" means if the argument is a set, so a configure_sets with this configuration...

(SetWithInsertSystem, SetWithAssertSystem).chain_ignore_deferred()

... is the last row.

chain cannot mix systems and sets, but before and after can mix, therefore these have more rows.

General observations regarding the two system:

  • the tests do not fail if insert_system is exclusive
  • the tests do not fail if insert_system is exclusive and assert_system is not exclusive

Third system affecting the outcome of the tests

Now I am adding a third, empty system and order them after the two above. I observed that this results in some test going green suddenly.

fn third() {}
insert-assert config by third config by config ✅ fixes the failing test of ...
each system system after 1 3 4 7 8 9 10
config tuple system before 1 3 4 7 8 9 10
config tuple system chain 4 7 8 9 10
each system set after 1 2 3 5 6 8 9 10
config tuple set before 1 3 4 7 8 9 10
set system after 1 2 3 4 5 7 8 9 10
set system before 1 2 3 5 6
set set after 1 2 3 5 6
set set before 1 2 3 5 6
set set chain 1 2 3 5 6

For example this is the first row with 3...

fn main() {
    App::new()
        .add_systems(
            Update, 
            (
                (insert_system, assert_system).chain_ignore_deferred(),
                third.after(insert_system).after(assert_system)
            )
        )
        .update();
}

... and this the second row with 3 ...

fn main() {
    App::new()
        .add_systems(
            Update, 
            (
                (insert_system, assert_system)
                    .chain_ignore_deferred().before(third),
                third
            )
        )
        .update();
}

... which both no longer fail.

General observations regarding the third system:

  • it does not matter if third is exclusive or not
  • If third is configured with _ignore_deferred variants, it does not affect the results of the first tests
  • If third is put before the two, not after, it does not affect the result of the first tests

Test file

I generated the tests with this file which also tests many other combinations that do not fail. It might come useful for testing fixes for this issue. Sorry if it looks horribly, that is how I generate tests. 🫣 Also worth noting that I double-checked that like 5 times but mistakes may only come up with a sixth time. I am just comfortable enough to list the results.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-BugAn unexpected or incorrect behaviorS-Needs-InvestigationThis issue requires detective work to figure out what's going wrong

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions