//! Insert dependency trees of startup systems into [Bevy `App`s][`App`]. //! //! Define dependency trees of startup systems for a Bevy `App` with the [`startup_tree`] macro. //! Insert trees into an `App` with the [`AddStartupTree::add_startup_tree`] extension method. It is //! strongly recommended that the macro is used to generate the data structure that is consumed by //! `add_startup_tree`. //! //! This is useful in scenarios where the startup logic is complex and would benefit from being //! broken up into multiple systems. Some of this startup logic can be run in parallel; others may //! require that certain systems run in a particular order. For example, a system that spawns a //! complex `bevy_ui` can get very large, deeply nested, and difficult to maintain. Such a system //! can be divided into multiple that work together to create the complex entity hierarchy. Systems //! that spawn children entities must run after the one that spawns the parent; this is where //! `bevy_startup_tree` becomes useful. //! //! # Bevy Compatibility //! //! `bevy` | `bevy_startup_tree` //! :--- | :--- //! `~0.14` | `>=0.6` //! `~0.13` | `>=0.5` //! `~0.12` | `>=0.4` //! `~0.11` | `>=0.3` //! `~0.10` | `>=0.2` //! `~0.9` | `~0.1` //! `<0.9` | Not supported //! //! # Behavior //! //! The systems that make up a startup tree, or nodes, are grouped by depth. The `startup_tree` //! macro generates a 2-D array where each row with index `i` contains the nodes at depth `i` in the //! tree. This 2-D array is consumed by `add_startup_tree` where each depth sub-array is combined //! into a [`SystemSet`]. //! //! ```rust no_run //! # use bevy_startup_tree::startup_tree; //! # fn sys_1_a() {} //! # fn sys_1_b() {} //! # fn sys_2() {} //! # std::mem::drop( //! startup_tree! { //! sys_1_a, //! sys_1_b => sys_2 //! } //! # ); //! ``` //! //! This macro invocation would generate the following 2-D array: //! //!
//! [ [sys_1_a, sys_1_b], [sys_2] ] //!//! //! Note that there are two sub-arrays: one for the nodes at depth 0 and one for depth 1. //! //! The sets for each sub-array run in order during the [`Startup` schedule][`Startup`]. Thus, the //! system sets inserted into the `Startup` schedule for the above tree would be: //! //! - Depth 0 tree set //! - Depth 0 tree flush set //! - Depth 1 tree set //! - Depth 1 tree flush set //! //! # Example //! //! The following is an example Bevy `App` with a startup tree. Note that the app will go through //! the startup phase, run a single frame cycle, and then exit. //! //! ```rust no_run //! use bevy::{log::LogPlugin, prelude::*}; //! use bevy_startup_tree::{startup_tree, AddStartupTree}; //! //! fn main() { //! App::new() //! .add_plugins((TaskPoolPlugin::default(), LogPlugin::default())) //! .add_systems(PreStartup, begin) //! .add_startup_tree(startup_tree! { //! sys_1_a, //! sys_1_b => sys_2_a, //! sys_1_c => { //! sys_2_b, //! sys_2_c => sys_3_a, //! }, //! }) //! .add_systems(PostStartup, end) //! .run(); //! } //! //! fn begin() { info!("[Begin]"); } //! fn sys_1_a() { info!("1.a"); } //! fn sys_1_b() { info!("1.b"); } //! fn sys_1_c() { info!("1.c"); } //! fn sys_2_a() { info!("2.a"); } //! fn sys_2_b() { info!("2.b"); } //! fn sys_2_c() { info!("2.c"); } //! fn sys_3_a() { info!("3.a"); } //! fn end() { info!("[End]"); } //! ``` //! //! ## Output //! //!
//! 2023-01-08T19:38:41.664766Z INFO example_app: [Begin] //! 2023-01-08T19:38:41.664906Z INFO example_app: 1.b //! 2023-01-08T19:38:41.664937Z INFO example_app: 1.c //! 2023-01-08T19:38:41.664959Z INFO example_app: 1.a //! 2023-01-08T19:38:41.665104Z INFO example_app: 2.c //! 2023-01-08T19:38:41.665133Z INFO example_app: 2.a //! 2023-01-08T19:38:41.665141Z INFO example_app: 2.b //! 2023-01-08T19:38:41.665204Z INFO example_app: 3.a //! 2023-01-08T19:38:41.665264Z INFO example_app: [End] //!//! //! Note that all of the logs for a depth (those with the same number) are grouped together because //! these systems belong to the same set. The sets run in order, causing the numbers to be sorted. //! However, the systems within a set do not, causing the letters for a given number to be //! unordered. //! //! The `begin` and `end` systems demonstrates when the tree runs during startup. To run a system //! before the tree, insert it into the [`PreStartup` schedule][`PreStartup`]. To run a system after //! the tree, insert it into the [`PostStartup` schedule][`PostStartup`]. //! //! [`App`]: https://docs.rs/bevy/~0.14/bevy/app/struct.App.html //! [`PostStartup`]: https://docs.rs/bevy/~0.14/bevy/app/struct.PostStartup.html //! [`PreStartup`]: https://docs.rs/bevy/~0.14/bevy/app/struct.PreStartup.html //! [`Startup`]: https://docs.rs/bevy/~0.14/bevy/app/struct.Startup.html //! [`SystemSet`]: https://docs.rs/bevy/~0.14/bevy/ecs/schedule/trait.SystemSet.html use std::fmt::Write; use bevy_app::{App, Startup}; use bevy_ecs::schedule::{IntoSystemConfigs, IntoSystemSetConfigs, SystemConfigs}; use rand::distributions::{Alphanumeric, DistString}; mod rng; mod schedule; use self::rng::get_rng; use self::schedule::StartupTreeLayer; /// Generate a tree of startup systems that can be consumed by [`AddStartupTree::add_startup_tree`]. /// /// See the [module docs](crate) for more information. pub use bevy_startup_tree_macros::startup_tree; const NAMESPACE_LEN: usize = 6; /// An extension trait for [`bevy::app::App`][`App`]. /// /// [`App`]: https://docs.rs/bevy/~0.14/bevy/app/struct.App.html pub trait AddStartupTree { /// Add a dependency tree of startup systems to the [`App`]. /// /// The input is an iterator over a 2-D array describing a tree where each row (inner iterator /// `I`) with index `i` contains the nodes at depth `i` in the tree. There is *no guarantee* /// that systems at the same depth with run in any specific order. It is strongly recommended /// that the [`startup_tree` macro](startup_tree) is used to generate the tree. /// /// See the [module docs](crate) for more information. /// /// [`App`]: https://docs.rs/bevy/~0.14/bevy/app/struct.App.html fn add_startup_tree