Crate bevy_ergo_plugin
source ·Expand description
Macros to make building bevy plugins more ergonomic (in my opinion).
Bevy’s API puts adding a system separate from its implementation. Separatng the system’s run conditions and other system parameters from its definition adds an extra layer of indirection, harming readability and adding boilerplate (.add_system
)
This crate’s purpose is to replace that API with a more ergonomic one, using attribute macros as markers for system parameters.
Not only does this allow for more readable system run conditions, but it also gives us fallible systems with logging much more cleanly, while still using bevy’s built-ins.
Putting the bevy_plugin attribute on the impl
block of a struct will turn that struct into a Bevy Plugin, which registers its associated functions as systems.
If you want to add extra functionality to your plugin’s Plugin::build
(like adding an asset or registering a component), the contents of any associated function named build
in a bevy_plugin attributed impl
block will be inserted into the generated Plugin::build
implementation.
The other macros are the aforementioned parameter markers to be put on your system definitions.
For any params not included by a specific marker, you can use the sysparam marker to define custom behavior.
Multiple parameter markers on a system do stack onto a single add_system
call, so you can add multiple run conditions and have it work as expected.
This crate is basically just doing code generation, so it doesn’t depend on bevy itself. It should work with any bevy version that has the functions you’re generating.
This crate has not been thoroughly tested, so there will probably be weird bugs I don’t know about.
Example
adapted from https://github.com/bevyengine/bevy/blob/latest/examples/ecs/run_conditions.rs
use bevy::prelude::*;
use bevy_ergo_plugin::*;
fn main() {
println!();
println!("For the first 2 seconds you will not be able to increment the counter");
println!("Once that time has passed you can press space, enter, left mouse, right mouse or touch the screen to increment the counter");
println!();
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(Game)
.run();
}
#[derive(Resource, Default)]
pub struct InputCounter(usize);
pub struct Game;
#[bevy_plugin]
impl Game {
#[resource_exists(InputCounter)]
#[run_if(Game::has_user_input)]
pub fn increment_input_counter(mut counter: ResMut<InputCounter>) {
counter.0 += 1;
}
#[run_if(resource_exists::<InputCounter>().and_then(
|counter: Res<InputCounter>| counter.is_changed() && !counter.is_added()
))]
pub fn print_input_counter(counter: Res<InputCounter>) {
println!("Input counter: {}", counter.0);
}
#[run_if(Game::time_passed(2.0))]
#[run_if(not(Game::time_passed(2.5)))]
pub fn print_time_message() {
println!(
"It has been more than 2 seconds since the program started and less than 2.5 seconds"
);
}
#[do_not_add]
pub fn has_user_input(
keyboard_input: Res<Input<KeyCode>>,
mouse_button_input: Res<Input<MouseButton>>,
touch_input: Res<Touches>,
) -> bool {
keyboard_input.just_pressed(KeyCode::Space)
|| keyboard_input.just_pressed(KeyCode::Return)
|| mouse_button_input.just_pressed(MouseButton::Left)
|| mouse_button_input.just_pressed(MouseButton::Right)
|| touch_input.any_just_pressed()
}
#[do_not_add]
pub fn time_passed(t: f32) -> impl FnMut(Local<f32>, Res<Time>) -> bool {
move |mut timer: Local<f32>, time: Res<Time>| {
*timer += time.delta_seconds();
*timer >= t
}
}
pub fn build(&self, app: &mut App) {
app.init_resource::<InputCounter>();
}
}
Attribute Macros
- system parameter marker attribute that generates
.add_system( system_name.after(arg) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(any_with_component::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.before(arg) )
- Put this attribute on an
impl
block of a struct to turn the struct into a plugin where the functions in theimpl
block are systems. Use the marker attributes on your systems to add parameters. A function namedbuild
can be used to add custom functionality to thePlugin::build
in the generatedPlugin
implementation. - system parameter marker attribute that generates
.add_system( system_name.pipe(system_adapter::dbg) )
- a marker attribute to exclude a function from being added
- system parameter marker attribute that generates
.add_system( system_name.pipe(system_adapter::error) )
- system parameter marker attribute that generates
.add_system( system_name.pipe(system_adapter::ignore) )
- system parameter marker attribute that generates
.add_system( system_name.in_base_set(arg) )
- system parameter marker attribute that generates
.add_system( system_name.in_schedule(arg) )
- system parameter marker attribute that generates
.add_system( system_name.in_set(arg) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(in_state(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.pipe(system_adapter::info) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(not(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.in_schedule(OnEnter(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(on_event::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.in_schedule(OnExit(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.in_set(OnUpdate(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.pipe(arg) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_added::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_changed::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_changed_or_removed::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_equals(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_exists::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_exists_and_changed::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_exists_and_equals(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(resource_removed::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(arg) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(run_once()) )
- system parameter marker attribute that generates
.add_system( system_name.on_startup() )
- system parameter marker attribute that generates
.add_system( system_name.run_if(state_changed::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(state_exists::<arg>()) )
- system parameter marker attribute that generates
.add_system( system_name.run_if(state_exists_and_equals(arg)) )
- system parameter marker attribute that generates
.add_system( system_name.arg )
- system parameter marker attribute that generates
.add_system( system_name.pipe(system_adapter::unwrap) )
- system parameter marker attribute that generates
.add_system( system_name.pipe(system_adapter::warn) )