Tainted\\Coders

Exclusive Systems

Bevy version: 0.14Last updated:

Normally you are not allowed to make changes to the world directly. Instead, we schedule commands which run in their own exclusive system: apply_deferred that runs once per frame.

Exclusive systems are systems that take a &mut World system parameter. This gives them a set of superpowers at the cost of not being able to be run in parallel. This makes them a less performant than your other systems.

fn exclusive_system(world: &mut World) {
  // ...
}

fn main() {
  App::new()
    .add_plugins(DefaultPlugins)
    .add_systems(Update, exclusive_system);
}

There are only a few other system parameters you can take once you decide to be exclusive:

QueryState and SystemState both have to be provided your world to retrieve their data, instead of being given directly through dependency injection

Another difference between these and your normal system parameters is that to access certain params won't work unless you cache them which can make it more complicated than it needs to be.

fn psudo_command_system(mut world: &mut World) {
  let mut system_state: SystemState<Commands> = SystemState::new(&mut world);

  let mut commands = system_state.get_mut(world);

  commands.spawn(Player);

  // We have to use this if we use `Commands`
  // and want them to be scheduled normally
  system_state.apply(world)
}

However, in most cases where we want to emulate a system, it can be much simpler to just call our other systems immediately from our exclusive system:

fn custom_system_runner(world: &mut World) {
  let system = world.register_system(hello_world);
  world.run_system(system);
}

This gets around all the gotchas from using the other exclusive system params.

Use cases

You can spawn entities immediately instead of scheduling them with commands.

fn spawn_immediately(world: &mut World) {
  world.spawn((Player));
}

This system is doing what the commands that get scheduled eventually do in their own system where they are given their own mutable access to the World.

A common use case for exclusive systems is in managing your scenes:

fn save_scene_system(world: &mut World) {
  let mut scene_world = World::new();

  let type_registry = world.resource::<AppTypeRegistry>().clone();
  scene_world.insert_resource(type_registry);

  let scene = DynamicScene::from_world(&scene_world);

  // ....
}

Sometimes we have situations where we don't know all our system parameters up front. Having full access to the world allows us to grab what we need dynamically.

Exclusive systems can be great for prototyping too. You can use them to write your game logic without worrying as much about exactly when and where you run your systems. Just call them directly when you need to and they execute immediately.