bevy_render/
extract_resource.rs1use core::marker::PhantomData;
2
3use bevy_app::{App, Plugin};
4use bevy_ecs::{component::Mutable, prelude::*};
5pub use bevy_render_macros::ExtractResource;
6use bevy_utils::once;
7
8use crate::{Extract, ExtractSchedule, RenderApp};
9
10pub trait ExtractResource<F = ()>: Resource {
19 type Source: Resource;
20
21 fn extract_resource(source: &Self::Source) -> Self;
23}
24
25pub struct ExtractResourcePlugin<R: ExtractResource<F>, F = ()>(PhantomData<(R, F)>);
34
35impl<R: ExtractResource<F>, F> Default for ExtractResourcePlugin<R, F> {
36 fn default() -> Self {
37 Self(PhantomData)
38 }
39}
40
41impl<R: ExtractResource<F, Mutability = Mutable>, F: 'static + Send + Sync> Plugin
42 for ExtractResourcePlugin<R, F>
43{
44 fn build(&self, app: &mut App) {
45 if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
46 render_app.add_systems(ExtractSchedule, extract_resource::<R, F>);
47 } else {
48 once!(bevy_log::error!(
49 "Render app did not exist when trying to add `extract_resource` for <{}>.",
50 core::any::type_name::<R>()
51 ));
52 }
53 }
54}
55
56pub fn extract_resource<R: ExtractResource<F, Mutability = Mutable>, F>(
58 mut commands: Commands,
59 main_resource: Extract<Option<Res<R::Source>>>,
60 target_resource: Option<ResMut<R>>,
61) {
62 if let Some(main_resource) = main_resource.as_ref() {
63 if let Some(mut target_resource) = target_resource {
64 if main_resource.is_changed() {
65 *target_resource = R::extract_resource(main_resource);
66 }
67 } else {
68 #[cfg(debug_assertions)]
69 if !main_resource.is_added() {
70 once!(bevy_log::warn!(
71 "Removing resource {} from render world not expected, adding using `Commands`.
72 This may decrease performance",
73 core::any::type_name::<R>()
74 ));
75 }
76
77 commands.insert_resource(R::extract_resource(main_resource));
78 }
79 }
80}