bevy_render/extract_param.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
use crate::MainWorld;
use bevy_ecs::{
component::Tick,
prelude::*,
system::{ReadOnlySystemParam, SystemMeta, SystemParam, SystemParamItem, SystemState},
world::unsafe_world_cell::UnsafeWorldCell,
};
use core::ops::{Deref, DerefMut};
/// A helper for accessing [`MainWorld`] content using a system parameter.
///
/// A [`SystemParam`] adapter which applies the contained `SystemParam` to the [`World`]
/// contained in [`MainWorld`]. This parameter only works for systems run
/// during the [`ExtractSchedule`](crate::ExtractSchedule).
///
/// This requires that the contained [`SystemParam`] does not mutate the world, as it
/// uses a read-only reference to [`MainWorld`] internally.
///
/// ## Context
///
/// [`ExtractSchedule`] is used to extract (move) data from the simulation world ([`MainWorld`]) to the
/// render world. The render world drives rendering each frame (generally to a `Window`).
/// This design is used to allow performing calculations related to rendering a prior frame at the same
/// time as the next frame is simulated, which increases throughput (FPS).
///
/// [`Extract`] is used to get data from the main world during [`ExtractSchedule`].
///
/// ## Examples
///
/// ```
/// use bevy_ecs::prelude::*;
/// use bevy_render::Extract;
/// use bevy_render::sync_world::RenderEntity;
/// # #[derive(Component)]
/// // Do make sure to sync the cloud entities before extracting them.
/// # struct Cloud;
/// fn extract_clouds(mut commands: Commands, clouds: Extract<Query<RenderEntity, With<Cloud>>>) {
/// for cloud in &clouds {
/// commands.entity(cloud).insert(Cloud);
/// }
/// }
/// ```
///
/// [`ExtractSchedule`]: crate::ExtractSchedule
/// [Window]: bevy_window::Window
pub struct Extract<'w, 's, P>
where
P: ReadOnlySystemParam + 'static,
{
item: SystemParamItem<'w, 's, P>,
}
#[doc(hidden)]
pub struct ExtractState<P: SystemParam + 'static> {
state: SystemState<P>,
main_world_state: <Res<'static, MainWorld> as SystemParam>::State,
}
// SAFETY: The only `World` access (`Res<MainWorld>`) is read-only.
unsafe impl<P> ReadOnlySystemParam for Extract<'_, '_, P> where P: ReadOnlySystemParam {}
// SAFETY: The only `World` access is properly registered by `Res<MainWorld>::init_state`.
// This call will also ensure that there are no conflicts with prior params.
unsafe impl<P> SystemParam for Extract<'_, '_, P>
where
P: ReadOnlySystemParam,
{
type State = ExtractState<P>;
type Item<'w, 's> = Extract<'w, 's, P>;
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
let mut main_world = world.resource_mut::<MainWorld>();
ExtractState {
state: SystemState::new(&mut main_world),
main_world_state: Res::<MainWorld>::init_state(world, system_meta),
}
}
#[inline]
unsafe fn validate_param(
state: &Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> bool {
// SAFETY: Read-only access to world data registered in `init_state`.
let result = unsafe { world.get_resource_by_id(state.main_world_state) };
let Some(main_world) = result else {
system_meta.try_warn_param::<&World>();
return false;
};
// SAFETY: Type is guaranteed by `SystemState`.
let main_world: &World = unsafe { main_world.deref() };
// SAFETY: We provide the main world on which this system state was initialized on.
unsafe {
SystemState::<P>::validate_param(
&state.state,
main_world.as_unsafe_world_cell_readonly(),
)
}
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
// SAFETY:
// - The caller ensures that `world` is the same one that `init_state` was called with.
// - The caller ensures that no other `SystemParam`s will conflict with the accesses we have registered.
let main_world = unsafe {
Res::<MainWorld>::get_param(
&mut state.main_world_state,
system_meta,
world,
change_tick,
)
};
let item = state.state.get(main_world.into_inner());
Extract { item }
}
}
impl<'w, 's, P> Deref for Extract<'w, 's, P>
where
P: ReadOnlySystemParam,
{
type Target = SystemParamItem<'w, 's, P>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.item
}
}
impl<'w, 's, P> DerefMut for Extract<'w, 's, P>
where
P: ReadOnlySystemParam,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.item
}
}
impl<'a, 'w, 's, P> IntoIterator for &'a Extract<'w, 's, P>
where
P: ReadOnlySystemParam,
&'a SystemParamItem<'w, 's, P>: IntoIterator,
{
type Item = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::Item;
type IntoIter = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
(&self.item).into_iter()
}
}