
Spiritual successor to #5205. Actual successor to #6865. # Objective Currently, system params are defined using three traits: `SystemParam`, `ReadOnlySystemParam`, `SystemParamState`. The behavior for each param is specified by the `SystemParamState` trait, while `SystemParam` simply defers to the state. Splitting the traits in this way makes it easier to implement within macros, but it increases the cognitive load. Worst of all, this approach requires each `MySystemParam` to have a public `MySystemParamState` type associated with it. ## Solution * Merge the trait `SystemParamState` into `SystemParam`. * Remove all trivial `SystemParam` state types. * `OptionNonSendMutState<T>`: you will not be missed. --- - [x] Fix/resolve the remaining test failure. ## Changelog * Removed the trait `SystemParamState`, merging its functionality into `SystemParam`. ## Migration Guide **Note**: this should replace the migration guide for #6865. This is relative to Bevy 0.9, not main. The traits `SystemParamState` and `SystemParamFetch` have been removed, and their functionality has been transferred to `SystemParam`. ```rust // Before (0.9) impl SystemParam for MyParam<'_, '_> { type State = MyParamState; } unsafe impl SystemParamState for MyParamState { fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { ... } } unsafe impl<'w, 's> SystemParamFetch<'w, 's> for MyParamState { type Item = MyParam<'w, 's>; fn get_param(&mut self, ...) -> Self::Item; } unsafe impl ReadOnlySystemParamFetch for MyParamState { } // After (0.10) unsafe impl SystemParam for MyParam<'_, '_> { type State = MyParamState; type Item<'w, 's> = MyParam<'w, 's>; fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State { ... } fn get_param<'w, 's>(state: &mut Self::State, ...) -> Self::Item<'w, 's>; } unsafe impl ReadOnlySystemParam for MyParam<'_, '_> { } ``` The trait `ReadOnlySystemParamFetch` has been replaced with `ReadOnlySystemParam`. ```rust // Before unsafe impl ReadOnlySystemParamFetch for MyParamState {} // After unsafe impl ReadOnlySystemParam for MyParam<'_, '_> {} ```
123 lines
3.6 KiB
Rust
123 lines
3.6 KiB
Rust
use crate::MainWorld;
|
|
use bevy_ecs::{
|
|
prelude::*,
|
|
system::{ReadOnlySystemParam, SystemMeta, SystemParam, SystemParamItem, SystemState},
|
|
};
|
|
use std::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 [`RenderStage::Extract`].
|
|
///
|
|
/// This requires that the contained [`SystemParam`] does not mutate the world, as it
|
|
/// uses a read-only reference to [`MainWorld`] internally.
|
|
///
|
|
/// ## Context
|
|
///
|
|
/// [`RenderStage::Extract`] 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 [`RenderStage::Extract`].
|
|
///
|
|
/// ## Examples
|
|
///
|
|
/// ```rust
|
|
/// use bevy_ecs::prelude::*;
|
|
/// use bevy_render::Extract;
|
|
/// # #[derive(Component)]
|
|
/// # struct Cloud;
|
|
/// fn extract_clouds(mut commands: Commands, clouds: Extract<Query<Entity, With<Cloud>>>) {
|
|
/// for cloud in &clouds {
|
|
/// commands.get_or_spawn(cloud).insert(Cloud);
|
|
/// }
|
|
/// }
|
|
/// ```
|
|
///
|
|
/// [`RenderStage::Extract`]: crate::RenderStage::Extract
|
|
/// [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: only accesses MainWorld resource with read only system params using Res,
|
|
// which is initialized in init()
|
|
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),
|
|
}
|
|
}
|
|
|
|
unsafe fn get_param<'w, 's>(
|
|
state: &'s mut Self::State,
|
|
system_meta: &SystemMeta,
|
|
world: &'w World,
|
|
change_tick: u32,
|
|
) -> Self::Item<'w, 's> {
|
|
let main_world = 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()
|
|
}
|
|
}
|