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}