Path: blob/main/crates/bevy_render/src/extract_param.rs
6595 views
use crate::MainWorld;1use bevy_ecs::{2component::Tick,3prelude::*,4query::FilteredAccessSet,5system::{6ReadOnlySystemParam, SystemMeta, SystemParam, SystemParamItem, SystemParamValidationError,7SystemState,8},9world::unsafe_world_cell::UnsafeWorldCell,10};11use core::ops::{Deref, DerefMut};1213/// A helper for accessing [`MainWorld`] content using a system parameter.14///15/// A [`SystemParam`] adapter which applies the contained `SystemParam` to the [`World`]16/// contained in [`MainWorld`]. This parameter only works for systems run17/// during the [`ExtractSchedule`](crate::ExtractSchedule).18///19/// This requires that the contained [`SystemParam`] does not mutate the world, as it20/// uses a read-only reference to [`MainWorld`] internally.21///22/// ## Context23///24/// [`ExtractSchedule`] is used to extract (move) data from the simulation world ([`MainWorld`]) to the25/// render world. The render world drives rendering each frame (generally to a `Window`).26/// This design is used to allow performing calculations related to rendering a prior frame at the same27/// time as the next frame is simulated, which increases throughput (FPS).28///29/// [`Extract`] is used to get data from the main world during [`ExtractSchedule`].30///31/// ## Examples32///33/// ```34/// use bevy_ecs::prelude::*;35/// use bevy_render::Extract;36/// use bevy_render::sync_world::RenderEntity;37/// # #[derive(Component)]38/// // Do make sure to sync the cloud entities before extracting them.39/// # struct Cloud;40/// fn extract_clouds(mut commands: Commands, clouds: Extract<Query<RenderEntity, With<Cloud>>>) {41/// for cloud in &clouds {42/// commands.entity(cloud).insert(Cloud);43/// }44/// }45/// ```46///47/// [`ExtractSchedule`]: crate::ExtractSchedule48/// [Window]: bevy_window::Window49pub struct Extract<'w, 's, P>50where51P: ReadOnlySystemParam + 'static,52{53item: SystemParamItem<'w, 's, P>,54}5556#[doc(hidden)]57pub struct ExtractState<P: SystemParam + 'static> {58state: SystemState<P>,59main_world_state: <Res<'static, MainWorld> as SystemParam>::State,60}6162// SAFETY: The only `World` access (`Res<MainWorld>`) is read-only.63unsafe impl<P> ReadOnlySystemParam for Extract<'_, '_, P> where P: ReadOnlySystemParam {}6465// SAFETY: The only `World` access is properly registered by `Res<MainWorld>::init_state`.66// This call will also ensure that there are no conflicts with prior params.67unsafe impl<P> SystemParam for Extract<'_, '_, P>68where69P: ReadOnlySystemParam,70{71type State = ExtractState<P>;72type Item<'w, 's> = Extract<'w, 's, P>;7374fn init_state(world: &mut World) -> Self::State {75let mut main_world = world.resource_mut::<MainWorld>();76ExtractState {77state: SystemState::new(&mut main_world),78main_world_state: Res::<MainWorld>::init_state(world),79}80}8182fn init_access(83state: &Self::State,84system_meta: &mut SystemMeta,85component_access_set: &mut FilteredAccessSet,86world: &mut World,87) {88Res::<MainWorld>::init_access(89&state.main_world_state,90system_meta,91component_access_set,92world,93);94}9596#[inline]97unsafe fn validate_param(98state: &mut Self::State,99_system_meta: &SystemMeta,100world: UnsafeWorldCell,101) -> Result<(), SystemParamValidationError> {102// SAFETY: Read-only access to world data registered in `init_state`.103let result = unsafe { world.get_resource_by_id(state.main_world_state) };104let Some(main_world) = result else {105return Err(SystemParamValidationError::invalid::<Self>(106"`MainWorld` resource does not exist",107));108};109// SAFETY: Type is guaranteed by `SystemState`.110let main_world: &World = unsafe { main_world.deref() };111// SAFETY: We provide the main world on which this system state was initialized on.112unsafe {113SystemState::<P>::validate_param(114&mut state.state,115main_world.as_unsafe_world_cell_readonly(),116)117}118}119120#[inline]121unsafe fn get_param<'w, 's>(122state: &'s mut Self::State,123system_meta: &SystemMeta,124world: UnsafeWorldCell<'w>,125change_tick: Tick,126) -> Self::Item<'w, 's> {127// SAFETY:128// - The caller ensures that `world` is the same one that `init_state` was called with.129// - The caller ensures that no other `SystemParam`s will conflict with the accesses we have registered.130let main_world = unsafe {131Res::<MainWorld>::get_param(132&mut state.main_world_state,133system_meta,134world,135change_tick,136)137};138let item = state.state.get(main_world.into_inner());139Extract { item }140}141}142143impl<'w, 's, P> Deref for Extract<'w, 's, P>144where145P: ReadOnlySystemParam,146{147type Target = SystemParamItem<'w, 's, P>;148149#[inline]150fn deref(&self) -> &Self::Target {151&self.item152}153}154155impl<'w, 's, P> DerefMut for Extract<'w, 's, P>156where157P: ReadOnlySystemParam,158{159#[inline]160fn deref_mut(&mut self) -> &mut Self::Target {161&mut self.item162}163}164165impl<'a, 'w, 's, P> IntoIterator for &'a Extract<'w, 's, P>166where167P: ReadOnlySystemParam,168&'a SystemParamItem<'w, 's, P>: IntoIterator,169{170type Item = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::Item;171type IntoIter = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::IntoIter;172173fn into_iter(self) -> Self::IntoIter {174(&self.item).into_iter()175}176}177178179