Skip to content

Conversation

@ItsDoot
Copy link
Contributor

@ItsDoot ItsDoot commented Nov 20, 2025

Objective

Bevy users occasionally ask for the ability to run specific SystemSets in a Schedule, commonly for unit testing behaviors. Beyond that, this functionality brings us closer to turning our Update, PostUpdate, etc schedules into system sets by giving system sets a power that previously only schedules had: the ability to be executed.

Solution

  • Added a new parameter to SystemExecutor::run: subgraph: Option<SystemSetKey>
    • If Some, the provided SystemSetKey is used to fetch a bitset of the systems that are part of the set (including transitively), which is used to filter the SystemExecutor to execute only those systems.
    • If None, the SystemExecutor functions as previously.
  • Added SystemSchedule::systems_in_set which holds a sparse mapping of system sets to bitsets of the systems part of that set.
    • This map is filled lazily upon the first time a system set is executed.
  • Added Schedule::run_system_set which invokes SystemExecutor::run with the given system set.
  • Added World/Commands::run_system_set/try_run_system_set which invokes Schedule::run_system_set.

Note: Schedule::run_system_set is not re-entrant.

Testing

  • Added two new tests, one for single-threaded and one for multi-threaded.
  • Added new doctests.
  • Added new benchmarks.

Future work

  • Make slotmap::SparseSecondaryMap work under alloc rather than std, so we can replace SystemSchedule::systems_in_sets's HashMap with it.

Showcase

You can now run a specific system set within a schedule without executing the entire
schedule! This is particularly useful for testing, debugging, or selectively running
parts of your game logic, all without needing to factor features out into separate
schedules:

use bevy::prelude::*;

#[derive(SystemSet, Clone, Copy, PartialEq, Eq, Debug, Hash)]
enum GameSystems {
    Physics,
    Combat,
    UI,
}

fn physics_system() { /* ... */ }
fn combat_system() { /* ... */ }
fn ui_system() { /* ... */ }

let mut schedule = Schedule::default();
schedule.add_systems((
    physics_system.in_set(GameSystems::Physics),
    combat_system.in_set(GameSystems::Combat),
    ui_system.in_set(GameSystems::UI),
));

let mut world = World::new();

// Run only the physics systems
schedule.run_system_set(&mut world, GameSystems::Physics);

// Run only the combat systems
schedule.run_system_set(&mut world, GameSystems::Combat);

// You can also run system sets from the World or via Commands:
world.run_system_set(MySchedule, MySet);
commands.run_system_set(MySchedule, MySet);

@ItsDoot ItsDoot added C-Feature A new feature, making something new possible A-ECS Entities, components, systems, and events M-Release-Note Work that should be called out in the blog due to impact D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Nov 20, 2025
@ItsDoot ItsDoot mentioned this pull request Nov 20, 2025
7 tasks
@janhohenheim
Copy link
Member

I don't feel qualified to review the code per-se, but I want to express my support for this PR. Yeeting schedules would be lovely, and this looks like a great step in this direction :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes M-Release-Note Work that should be called out in the blog due to impact S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants