Exclusive Systems
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:
Local<T>
: Local parameter that holds state between invocationsSystemState<P>
:P
are normal system parameters, this lets us act like a normal systemQueryState<Q, F = ()>
: Just like aQuery
, provides scoped access to the world
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.