#Cleaner syntax for expressing system ordering

27 messages · Page 1 of 1 (latest)

sleek epoch
#
app.add_systems(
            (
                // NOTE: move_ant needs to run first to avoid situation where ant falls + moves in same frame
                move_ant,
                // TODO: sand/ant gravity systems can run in parallel, but not clear how to express that without allowing render to run
                sand_gravity_system.after(move_ant),
                ant_gravity_system.after(sand_gravity_system),
                // Rendering systems need to run after all other systems, but can run in any order.
                render_translation
                    .after(ant_gravity_system)
                    .ambiguous_with(render_scale)
                    .ambiguous_with(render_rotation)
                    .ambiguous_with(render_carrying),
                render_scale
                    .after(ant_gravity_system)
                    .ambiguous_with(render_translation)
                    .ambiguous_with(render_rotation)
                    .ambiguous_with(render_carrying),
                render_rotation
                    .after(ant_gravity_system)
                    .ambiguous_with(render_translation)
                    .ambiguous_with(render_scale)
                    .ambiguous_with(render_carrying),
                render_carrying
                    .after(ant_gravity_system)
                    .ambiguous_with(render_translation)
                    .ambiguous_with(render_scale)
                    .ambiguous_with(render_rotation),
            )
                .in_schedule(CoreSchedule::FixedUpdate),
        );

Is there a way to express this with less verbosity? I have a set of render systems which are strictly UI updates and can run in any order, but they need to run after all the model state updates.

wary goblet
#

Assuming the render_* systems can't run in parallel because you used ambiguous_with I'd just use chain() to run all these systems in order.

(
    move_ant,
    sand_gravity_system,
    ant_gravity_system,
    render_translation,
    render_scale,
    render_rotation,
    render_carrying,
)
    .chain()
    .in_schedule(CoreSchedule::FixedUpdate)
sleek epoch
#

Hmm? I thought using ambiguous_with allowed them to run parallel while suppressing the warning?

#
fn ambiguous_with<M>(self, set: impl IntoSystemSet<M>) -> Config
Suppress warnings and errors that would result from this system having ambiguities (conflicting access but indeterminate order) with systems in set.
#

So ideally the render_* systems would be able to run in parallel

#

I think I have an idea though

wary goblet
sleek epoch
#

@wary goblet Yeah? So there are still ambiguities in the run order and thus they run in parallel, no?

#

Otherwise it wouldn't just be suppressing warnings it would be effectively chaining their order

wary goblet
#

The reason you get the warnings is that these systems can't run in parallel because of "conflicting access" and have an "indeterminate(unspecified) order".
ambiguous_with suppresses the warning and leaves them to run in a random order.

sleek epoch
#

How do I allow them to run in parallel then?

trail salmon
#

What data are they each modifying?

#

Just copy paste their parameters.

sleek epoch
#

They're each updating a different property of transform. As an example:

pub fn render_scale(mut query: Query<(&mut Transform, &AntFacing), Changed<AntFacing>>) {
    for (mut transform, &facing) in query.iter_mut() {
        let x_flip = if facing == AntFacing::Left { -1.0 } else { 1.0 };
        transform.scale = Vec3::new(x_flip, 1.0, 1.0);
    }
}

pub fn render_rotation(mut query: Query<(&mut Transform, &AntAngle), Changed<AntAngle>>) {
    for (mut transform, &angle) in query.iter_mut() {
        transform.rotation = Quat::from_rotation_z(angle.as_radians());
    }
}
trail salmon
#

The issue is that they are all trying to have mutable access to Transform.

sleek epoch
#

Okay, so I should just run them sequentially?

trail salmon
#

It would be the easy solution out, but there are options, it would require some restructuring.

sleek epoch
#

Or use a bunch of Without<T> and merge the systems into one that affects transform

trail salmon
#

Yeah, for example, are AntFacing and AntAngle exclusive to eachother or should a transform be able to have both?

sleek epoch
#

Or I guess I could use a single query and make some of the components optional

#

yeah, those ones are sensible to combine, but render_translation works on entities that don't necessarily have AntFacing/AntAngle components

#

so I would either need separate queries and work to make them exclusive, make part of the query optional, or split systems

trail salmon
#

You could also chain them and use ::par_iter_mut().for_each(|mut item|{ ... }); instead of ::item_mut()

sleek epoch
#

anyway, thanks for clarifying, I just misunderstood the docs on the warning bit. I misinterpreted the random ordering as parallelization

trail salmon
#

That way the query is parallel, but they still have to wait for eachother.

sleek epoch
#

I'll have to do some reading up on that one 🙂 Appreciate it

trail salmon
#

Good luck with your project!