 e4b368721d
			
		
	
	
		e4b368721d
		
			
		
	
	
	
	
		
			
			I'm adopting this ~~child~~ PR. # Objective - Working with exclusive world access is not always easy: in many cases, a standard system or three is more ergonomic to write, and more modularly maintainable. - For small, one-off tasks (commonly handled with scripting), running an event-reader system incurs a small but flat overhead cost and muddies the schedule. - Certain forms of logic (e.g. turn-based games) want very fine-grained linear and/or branching control over logic. - SystemState is not automatically cached, and so performance can suffer and change detection breaks. - Fixes https://github.com/bevyengine/bevy/issues/2192. - Partial workaround for https://github.com/bevyengine/bevy/issues/279. ## Solution - Adds a SystemRegistry resource to the World, which stores initialized systems keyed by their SystemSet. - Allows users to call world.run_system(my_system) and commands.run_system(my_system), without re-initializing or losing state (essential for change detection). - Add a Callback type to enable convenient use of dynamic one shot systems and reduce the mental overhead of working with Box<dyn SystemSet>. - Allow users to run systems based on their SystemSet, enabling more complex user-made abstractions. ## Future work - Parameterized one-shot systems would improve reusability and bring them closer to events and commands. The API could be something like run_system_with_input(my_system, my_input) and use the In SystemParam. - We should evaluate the unification of commands and one-shot systems since they are two different ways to run logic on demand over a World. ### Prior attempts - https://github.com/bevyengine/bevy/pull/2234 - https://github.com/bevyengine/bevy/pull/2417 - https://github.com/bevyengine/bevy/pull/4090 - https://github.com/bevyengine/bevy/pull/7999 This PR continues the work done in https://github.com/bevyengine/bevy/pull/7999. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Federico Rinaldi <gisquerin@gmail.com> Co-authored-by: MinerSebas <66798382+MinerSebas@users.noreply.github.com> Co-authored-by: Aevyrie <aevyrie@gmail.com> Co-authored-by: Alejandro Pascual Pozo <alejandro.pascual.pozo@gmail.com> Co-authored-by: Rob Parrett <robparrett@gmail.com> Co-authored-by: François <mockersf@gmail.com> Co-authored-by: Dmytro Banin <banind@cs.washington.edu> Co-authored-by: James Liu <contact@jamessliu.com>
		
			
				
	
	
		
			60 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			60 lines
		
	
	
		
			1.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| //! Demonstrates the use of "one-shot systems", which run once when triggered.
 | |
| //!
 | |
| //! These can be useful to help structure your logic in a push-based fashion,
 | |
| //! reducing the overhead of running extremely rarely run systems
 | |
| //! and improving schedule flexibility.
 | |
| //!
 | |
| //! See the [`World::run_system`](bevy::ecs::World::run_system) or
 | |
| //! [`World::run_system_once`](bevy::ecs::World::run_system_once) docs for more
 | |
| //! details.
 | |
| 
 | |
| use bevy::{
 | |
|     ecs::system::{RunSystemOnce, SystemId},
 | |
|     prelude::*,
 | |
| };
 | |
| 
 | |
| fn main() {
 | |
|     App::new()
 | |
|         .add_systems(Startup, (count_entities, setup))
 | |
|         .add_systems(PostUpdate, count_entities)
 | |
|         .add_systems(Update, evaluate_callbacks)
 | |
|         .run();
 | |
| }
 | |
| 
 | |
| // Any ordinary system can be run via commands.run_system or world.run_system.
 | |
| fn count_entities(all_entities: Query<()>) {
 | |
|     dbg!(all_entities.iter().count());
 | |
| }
 | |
| 
 | |
| #[derive(Component)]
 | |
| struct Callback(SystemId);
 | |
| 
 | |
| #[derive(Component)]
 | |
| struct Triggered;
 | |
| 
 | |
| fn setup(world: &mut World) {
 | |
|     let button_pressed_id = world.register_system(button_pressed);
 | |
|     world.spawn((Callback(button_pressed_id), Triggered));
 | |
|     // This entity does not have a Triggered component, so its callback won't run.
 | |
|     let slider_toggled_id = world.register_system(slider_toggled);
 | |
|     world.spawn(Callback(slider_toggled_id));
 | |
|     world.run_system_once(count_entities);
 | |
| }
 | |
| 
 | |
| fn button_pressed() {
 | |
|     println!("A button was pressed!");
 | |
| }
 | |
| 
 | |
| fn slider_toggled() {
 | |
|     println!("A slider was toggled!");
 | |
| }
 | |
| 
 | |
| /// Runs the systems associated with each `Callback` component if the entity also has a Triggered component.
 | |
| ///
 | |
| /// This could be done in an exclusive system rather than using `Commands` if preferred.
 | |
| fn evaluate_callbacks(query: Query<&Callback, With<Triggered>>, mut commands: Commands) {
 | |
|     for callback in query.iter() {
 | |
|         commands.run_system(callback.0);
 | |
|     }
 | |
| }
 |