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