wde_renderer/sync/
extract_resource_plugin.rs

1use std::marker::PhantomData;
2
3use bevy::prelude::*;
4
5use crate::core::{Extract, ExtractWorld, RenderApp};
6
7/// Plugin for extracting a resource from the main world to be used in the render world.
8/// This plugin will automatically add a system to extract the resource of the corresponding type from the main world and insert it into the render world.
9///
10/// Note:
11/// - The resource to extract must implement the [`ExtractResource`] trait.
12/// - If the resource already exists in the render world, it will be updated with the new value from the main world. Otherwise, it will be inserted as a new resource in the render world.
13/// - The update will only happen if the resource in the main world has changed, to avoid unnecessary updates and potential performance issues.
14/// - The marker type `F` is only used as a way to bypass the orphan rules.
15pub struct ExtractResourcePlugin<R: ExtractResource<F>, F = ()>(PhantomData<(R, F)>);
16impl<R: ExtractResource<F>, F> Default for ExtractResourcePlugin<R, F> {
17    fn default() -> Self {
18        Self(PhantomData)
19    }
20}
21impl<R: ExtractResource<F>, F: 'static + Send + Sync> Plugin for ExtractResourcePlugin<R, F> {
22    fn build(&self, app: &mut App) {
23        app.get_sub_app_mut(RenderApp)
24            .unwrap()
25            .add_systems(Extract, extract::<R, F>);
26    }
27}
28
29/// Trait for extracting a resource from the main world to be used in the render world. See [`ExtractResourcePlugin`].
30pub trait ExtractResource<F = ()>: Resource {
31    type Source: Resource;
32
33    /// Extracts the resource from the main world to be used in the render world.
34    fn extract(source: &Self::Source) -> Self;
35}
36
37/// Extracts the resource of the corresponding [`Resource`] type
38fn extract<R: ExtractResource<F>, F>(
39    mut commands: Commands,
40    main_resource: ExtractWorld<Option<Res<R::Source>>>,
41    render_resource: Option<ResMut<R>>
42) {
43    if let Some(main_resource) = main_resource.as_ref() {
44        if let Some(mut render_resource) = render_resource {
45            if main_resource.is_changed() {
46                *render_resource = R::extract(main_resource);
47            }
48        } else {
49            commands.insert_resource(R::extract(main_resource));
50        }
51    }
52}