bevy_extract/
extract_instances.rs1use core::marker::PhantomData;
8
9use bevy_app::{App, AppLabel, Plugin};
10use bevy_camera::visibility::ViewVisibility;
11use bevy_derive::{Deref, DerefMut};
12use bevy_ecs::{
13 prelude::Entity,
14 query::{QueryFilter, QueryItem, ReadOnlyQueryData},
15 resource::Resource,
16 system::{Query, ResMut},
17};
18
19use crate::sync_world::MainEntityHashMap;
20use crate::{Extract, ExtractSchedule};
21
22pub trait ExtractInstance<L: AppLabel>: Send + Sync + Sized + 'static {
32 type QueryData: ReadOnlyQueryData;
34 type QueryFilter: QueryFilter;
36
37 fn extract(item: QueryItem<'_, '_, Self::QueryData>) -> Option<Self>;
39}
40
41#[derive(Default)]
47pub struct ExtractInstancesPlugin<EI, L>
48where
49 EI: ExtractInstance<L>,
50 L: AppLabel,
51{
52 only_extract_visible: bool,
53 marker: PhantomData<fn() -> (L, EI)>,
54}
55
56#[derive(Resource, Deref, DerefMut)]
58pub struct ExtractedInstances<EI, L>(#[deref] MainEntityHashMap<EI>, PhantomData<L>)
59where
60 EI: ExtractInstance<L>,
61 L: AppLabel;
62
63impl<EI, L> Default for ExtractedInstances<EI, L>
64where
65 EI: ExtractInstance<L>,
66 L: AppLabel,
67{
68 fn default() -> Self {
69 Self(Default::default(), PhantomData)
70 }
71}
72
73impl<EI, L> ExtractInstancesPlugin<EI, L>
74where
75 EI: ExtractInstance<L>,
76 L: AppLabel,
77{
78 pub fn new() -> Self {
81 Self {
82 only_extract_visible: false,
83 marker: PhantomData,
84 }
85 }
86
87 pub fn extract_visible() -> Self {
90 Self {
91 only_extract_visible: true,
92 marker: PhantomData,
93 }
94 }
95}
96
97impl<EI, L> Plugin for ExtractInstancesPlugin<EI, L>
98where
99 EI: ExtractInstance<L>,
100 L: AppLabel + Default,
101{
102 fn build(&self, app: &mut App) {
103 if let Some(sub_app) = app.get_sub_app_mut(L::default()) {
104 sub_app.init_resource::<ExtractedInstances<EI, L>>();
105 if self.only_extract_visible {
106 sub_app.add_systems(ExtractSchedule, extract_visible::<EI, L>);
107 } else {
108 sub_app.add_systems(ExtractSchedule, extract_all::<EI, L>);
109 }
110 }
111 }
112}
113
114fn extract_all<EI, L>(
115 mut extracted_instances: ResMut<ExtractedInstances<EI, L>>,
116 query: Extract<Query<(Entity, EI::QueryData), EI::QueryFilter>>,
117) where
118 EI: ExtractInstance<L>,
119 L: AppLabel,
120{
121 extracted_instances.clear();
122 for (entity, other) in &query {
123 if let Some(extract_instance) = EI::extract(other) {
124 extracted_instances.insert(entity.into(), extract_instance);
125 }
126 }
127}
128
129fn extract_visible<EI, L>(
130 mut extracted_instances: ResMut<ExtractedInstances<EI, L>>,
131 query: Extract<Query<(Entity, &ViewVisibility, EI::QueryData), EI::QueryFilter>>,
132) where
133 EI: ExtractInstance<L>,
134 L: AppLabel,
135{
136 extracted_instances.clear();
137 for (entity, view_visibility, other) in &query {
138 if view_visibility.get()
139 && let Some(extract_instance) = EI::extract(other)
140 {
141 extracted_instances.insert(entity.into(), extract_instance);
142 }
143 }
144}