`SystemRunner` param - run systems inside other systems
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## What problem does this solve or what need does it fill?
Currently ways of running systems from other systems are very limited. This proposal aims to provide a way to easily run system as a `SystemParam`
## What solution would you like?
Add a `SystemParam` - `SystemRunner`
```rust
#[derive(Default)]
struct MySystem;
impl System for MySystem {
In = In;
Out = String;
//...
}
fn running_my_system(mut runner: SystemRunner) {
let output = runner.run(50);
info!("Output of MySystem: {output}");
}
```
### Unergonomic `System` implementation
To use this param, user would have to explicitly specify the type of the system they will use. Implementing `System` trait on it's own is hard - unsafe code is not something users want to deal with. [`FunctionSystem`](https://dev-docs.bevyengine.org/bevy/ecs/system/struct.FunctionSystem.html)s are the main way people are used to working with the bevy systems, but they don't implement [`FromWorld`](https://dev-docs.bevyengine.org/bevy/ecs/prelude/trait.FromWorld.html), and even if it did, you would have to either specify the marker or box every system.
So, it would be nice to have a macro that labels a function system with a specified type name.
```rust
#[system(MySystem)]
pub fn my_system(query: Query<&mut MyComponent>, resourse: Res) -> i32 {
//...
}
```
expands to
```rust
pub struct MySystem(SystemState<(Query<'static, 'static, &'static mut MyComponent>, Res<'static, MyRes>)>);
impl FromWorld for MySystem {
fn from_world(world: &mut World) -> Self {
MySystem(SystemState::new(world))
}
}
impl System for MySystem {
//... Basically the same as FunctionSystem implementation
}
```
### Needed controversial change
There is a conflict between [`System::update_archetype_component_access`](https://dev-docs.bevyengine.org/bevy/ecs/prelude/trait.System.html#tymethod.update_archetype_component_access) and [`SystemParam::new_archetype`](https://dev-docs.bevyengine.org/bevy/ecs/system/trait.SystemParam.html#method.new_archetype). You can't call `update_archetype_component_access` from `new_archetype`. Without that you wouldn't be able to call `update_archetype_component_access` on an inner system and simultaneously have access rights to run the system.
We can add a `new_archetype` method to `System` trait or `update_archetype_component_access` to `SystemParam` trait. We can pass `UnsafeWorldCell` to the `new_archetype`.
The best option in my opinion - add a `new_archetype` method to the `System` trait. There will be system-specific code for updating access. `update_archetype_component_access` will have a default implementation common for all systems. It will be basically the same as the current `FunctionSystem`'s implementation. Systems would also need a method that exposes system's archetype generation for `update_archetype_component_access` to have default implementation. Method that exposes archetype generation should be fallible so that ZST systems can say that they don't need to update archetype access.
Contributor guide
Assessment
This issue has not been assessed yet.