From 330160cf14dcc29ecdeb0c7a5a1fceadadcd6473 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Tue, 15 Feb 2022 21:53:52 +0000 Subject: [PATCH] SystemState usage docs (#3783) # Objective - `SystemStates` rock for dealing with exclusive world access, but are hard to figure out how to use. - Fixes #3341. ## Solution - Clearly document how to use `SystemState`, and why they're useful as an end-user. --- crates/bevy_ecs/src/system/function_system.rs | 76 +++++++++++++++++++ crates/bevy_ecs/src/world/mod.rs | 15 +++- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 36835c1d90..a92f89bc7a 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -56,6 +56,82 @@ impl SystemMeta { // TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference // (to avoid the need for unwrapping to retrieve SystemMeta) /// Holds on to persistent state required to drive [`SystemParam`] for a [`System`]. +/// +/// This is a very powerful and convenient tool for working with exclusive world access, +/// allowing you to fetch data from the [`World`] as if you were running a [`System`]. +/// +/// Borrow-checking is handled for you, allowing you to mutably access multiple compatible system parameters at once, +/// and arbitrary system parameters (like [`EventWriter`](crate::event::EventWriter)) can be conveniently fetched. +/// +/// For an alternative approach to split mutable access to the world, see [`World::resource_scope`]. +/// +/// # Warning +/// +/// [`SystemState`] values created can be cached to improve performance, +/// and *must* be cached and reused in order for system parameters that rely on local state to work correctly. +/// These include: +/// - [`Added`](crate::query::Added) and [`Changed`](crate::query::Changed) query filters +/// - [`Local`](crate::system::Local) variables that hold state +/// - [`EventReader`](crate::event::EventReader) system parameters, which rely on a [`Local`](crate::system::Local) to track which events have been seen +/// +/// # Example +/// +/// Basic usage: +/// ```rust +/// use bevy_ecs::prelude::*; +/// use bevy_ecs::{system::SystemState}; +/// use bevy_ecs::event::Events; +/// +/// struct MyEvent; +/// struct MyResource(u32); +/// +/// #[derive(Component)] +/// struct MyComponent; +/// +/// // Work directly on the `World` +/// let mut world = World::new(); +/// world.init_resource::>(); +/// +/// // Construct a `SystemState` struct, passing in a tuple of `SystemParam` +/// // as if you were writing an ordinary system. +/// let mut system_state: SystemState<( +/// EventWriter, +/// Option>, +/// Query<&MyComponent>, +/// )> = SystemState::new(&mut world); +/// +/// // Use system_state.get_mut(&mut world) and unpack your system parameters into variables! +/// // system_state.get(&world) provides read-only versions of your system parameters instead. +/// let (event_writer, maybe_resource, query) = system_state.get_mut(&mut world); +/// ``` +/// Caching: +/// ```rust +/// use bevy_ecs::prelude::*; +/// use bevy_ecs::{system::SystemState}; +/// use bevy_ecs::event::Events; +/// +/// struct MyEvent; +/// struct CachedSystemState<'w, 's>{ +/// event_state: SystemState> +/// } +/// +/// // Create and store a system state once +/// let mut world = World::new(); +/// world.init_resource::>(); +/// let initial_state: SystemState> = SystemState::new(&mut world); +/// +/// // The system state is cached in a resource +/// world.insert_resource(CachedSystemState{event_state: initial_state}); +/// +/// // Later, fetch the cached system state, saving on overhead +/// world.resource_scope(|world, mut cached_state: Mut| { +/// let mut event_reader = cached_state.event_state.get_mut(world); +/// +/// for events in event_reader.iter(){ +/// println!("Hello World!"); +/// }; +/// }); +/// ``` pub struct SystemState { meta: SystemMeta, param_state: ::Fetch, diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index ad037819e8..b130d7a547 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -34,6 +34,12 @@ pub use identifier::WorldId; /// component type. Entity components can be created, updated, removed, and queried using a given /// [World]. /// +/// For complex access patterns involving [`SystemParam`](crate::system::SystemParam), +/// consider using [`SystemState`](crate::system::SystemState). +/// +/// To mutate different parts of the world simultaneously, +/// use [`World::resource_scope`] or [`SystemState`](crate::system::SystemState). +/// /// # Resources /// /// Worlds can also store *resources*, which are unique instances of a given type that don't @@ -926,9 +932,12 @@ impl World { } } - /// Temporarily removes the requested resource from this [World], then re-adds it before - /// returning. This enables safe mutable access to a resource while still providing mutable - /// world access + /// Temporarily removes the requested resource from this [`World`], then re-adds it before returning. + /// + /// This enables safe simultaneous mutable access to both a resource and the rest of the [`World`]. + /// For more complex access patterns, consider using [`SystemState`](crate::system::SystemState). + /// + /// # Example /// ``` /// use bevy_ecs::{component::Component, world::{World, Mut}}; /// #[derive(Component)]