1use crate::{App, AppLabel, InternedAppLabel, Plugin, Plugins, PluginsState};
2use bevy_ecs::{
3 event::EventRegistry,
4 prelude::*,
5 schedule::{InternedScheduleLabel, ScheduleBuildSettings, ScheduleLabel},
6 system::SystemId,
7};
8
9#[cfg(feature = "trace")]
10use bevy_utils::tracing::info_span;
11use bevy_utils::{HashMap, HashSet};
12use std::fmt::Debug;
13
14type ExtractFn = Box<dyn Fn(&mut World, &mut World) + Send>;
15
16pub struct SubApp {
60 world: World,
62 pub(crate) plugin_registry: Vec<Box<dyn Plugin>>,
64 pub(crate) plugin_names: HashSet<String>,
67 pub(crate) plugin_build_depth: usize,
69 pub(crate) plugins_state: PluginsState,
70 pub update_schedule: Option<InternedScheduleLabel>,
72 extract: Option<ExtractFn>,
75}
76
77impl Debug for SubApp {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 write!(f, "SubApp")
80 }
81}
82
83impl Default for SubApp {
84 fn default() -> Self {
85 let mut world = World::new();
86 world.init_resource::<Schedules>();
87 Self {
88 world,
89 plugin_registry: Vec::default(),
90 plugin_names: HashSet::default(),
91 plugin_build_depth: 0,
92 plugins_state: PluginsState::Adding,
93 update_schedule: None,
94 extract: None,
95 }
96 }
97}
98
99impl SubApp {
100 pub fn new() -> Self {
102 Self::default()
103 }
104
105 fn run_as_app<F>(&mut self, f: F)
108 where
109 F: FnOnce(&mut App),
110 {
111 let mut app = App::empty();
112 std::mem::swap(self, &mut app.sub_apps.main);
113 f(&mut app);
114 std::mem::swap(self, &mut app.sub_apps.main);
115 }
116
117 pub fn world(&self) -> &World {
119 &self.world
120 }
121
122 pub fn world_mut(&mut self) -> &mut World {
124 &mut self.world
125 }
126
127 pub fn run_default_schedule(&mut self) {
131 if self.is_building_plugins() {
132 panic!("SubApp::update() was called while a plugin was building.");
133 }
134
135 if let Some(label) = self.update_schedule {
136 self.world.run_schedule(label);
137 }
138 }
139
140 pub fn update(&mut self) {
142 self.run_default_schedule();
143 self.world.clear_trackers();
144 }
145
146 pub fn extract(&mut self, world: &mut World) {
151 if let Some(f) = self.extract.as_mut() {
152 f(world, &mut self.world);
153 }
154 }
155
156 pub fn set_extract<F>(&mut self, extract: F) -> &mut Self
160 where
161 F: Fn(&mut World, &mut World) + Send + 'static,
162 {
163 self.extract = Some(Box::new(extract));
164 self
165 }
166
167 pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
169 self.world.insert_resource(resource);
170 self
171 }
172
173 pub fn init_resource<R: Resource + FromWorld>(&mut self) -> &mut Self {
175 self.world.init_resource::<R>();
176 self
177 }
178
179 pub fn add_systems<M>(
181 &mut self,
182 schedule: impl ScheduleLabel,
183 systems: impl IntoSystemConfigs<M>,
184 ) -> &mut Self {
185 let mut schedules = self.world.resource_mut::<Schedules>();
186 schedules.add_systems(schedule, systems);
187
188 self
189 }
190
191 pub fn register_system<I: 'static, O: 'static, M, S: IntoSystem<I, O, M> + 'static>(
193 &mut self,
194 system: S,
195 ) -> SystemId<I, O> {
196 self.world.register_system(system)
197 }
198
199 #[track_caller]
201 pub fn configure_sets(
202 &mut self,
203 schedule: impl ScheduleLabel,
204 sets: impl IntoSystemSetConfigs,
205 ) -> &mut Self {
206 let mut schedules = self.world.resource_mut::<Schedules>();
207 schedules.configure_sets(schedule, sets);
208 self
209 }
210
211 pub fn add_schedule(&mut self, schedule: Schedule) -> &mut Self {
213 let mut schedules = self.world.resource_mut::<Schedules>();
214 schedules.insert(schedule);
215 self
216 }
217
218 pub fn init_schedule(&mut self, label: impl ScheduleLabel) -> &mut Self {
220 let label = label.intern();
221 let mut schedules = self.world.resource_mut::<Schedules>();
222 if !schedules.contains(label) {
223 schedules.insert(Schedule::new(label));
224 }
225 self
226 }
227
228 pub fn get_schedule(&self, label: impl ScheduleLabel) -> Option<&Schedule> {
230 let schedules = self.world.get_resource::<Schedules>()?;
231 schedules.get(label)
232 }
233
234 pub fn get_schedule_mut(&mut self, label: impl ScheduleLabel) -> Option<&mut Schedule> {
236 let schedules = self.world.get_resource_mut::<Schedules>()?;
237 schedules.into_inner().get_mut(label)
240 }
241
242 pub fn edit_schedule(
244 &mut self,
245 label: impl ScheduleLabel,
246 mut f: impl FnMut(&mut Schedule),
247 ) -> &mut Self {
248 let label = label.intern();
249 let mut schedules = self.world.resource_mut::<Schedules>();
250 if !schedules.contains(label) {
251 schedules.insert(Schedule::new(label));
252 }
253
254 let schedule = schedules.get_mut(label).unwrap();
255 f(schedule);
256
257 self
258 }
259
260 pub fn configure_schedules(
262 &mut self,
263 schedule_build_settings: ScheduleBuildSettings,
264 ) -> &mut Self {
265 self.world_mut()
266 .resource_mut::<Schedules>()
267 .configure_schedules(schedule_build_settings);
268 self
269 }
270
271 pub fn allow_ambiguous_component<T: Component>(&mut self) -> &mut Self {
273 self.world_mut().allow_ambiguous_component::<T>();
274 self
275 }
276
277 pub fn allow_ambiguous_resource<T: Resource>(&mut self) -> &mut Self {
279 self.world_mut().allow_ambiguous_resource::<T>();
280 self
281 }
282
283 #[track_caller]
285 pub fn ignore_ambiguity<M1, M2, S1, S2>(
286 &mut self,
287 schedule: impl ScheduleLabel,
288 a: S1,
289 b: S2,
290 ) -> &mut Self
291 where
292 S1: IntoSystemSet<M1>,
293 S2: IntoSystemSet<M2>,
294 {
295 let schedule = schedule.intern();
296 let mut schedules = self.world.resource_mut::<Schedules>();
297
298 schedules.ignore_ambiguity(schedule, a, b);
299
300 self
301 }
302
303 pub fn add_event<T>(&mut self) -> &mut Self
305 where
306 T: Event,
307 {
308 if !self.world.contains_resource::<Events<T>>() {
309 EventRegistry::register_event::<T>(self.world_mut());
310 }
311
312 self
313 }
314
315 pub fn add_plugins<M>(&mut self, plugins: impl Plugins<M>) -> &mut Self {
317 self.run_as_app(|app| plugins.add_to_app(app));
318 self
319 }
320
321 pub fn is_plugin_added<T>(&self) -> bool
323 where
324 T: Plugin,
325 {
326 self.plugin_names.contains(std::any::type_name::<T>())
327 }
328
329 pub fn get_added_plugins<T>(&self) -> Vec<&T>
331 where
332 T: Plugin,
333 {
334 self.plugin_registry
335 .iter()
336 .filter_map(|p| p.downcast_ref())
337 .collect()
338 }
339
340 pub(crate) fn is_building_plugins(&self) -> bool {
342 self.plugin_build_depth > 0
343 }
344
345 #[inline]
347 pub fn plugins_state(&mut self) -> PluginsState {
348 match self.plugins_state {
349 PluginsState::Adding => {
350 let mut state = PluginsState::Ready;
351 let plugins = std::mem::take(&mut self.plugin_registry);
352 self.run_as_app(|app| {
353 for plugin in &plugins {
354 if !plugin.ready(app) {
355 state = PluginsState::Adding;
356 return;
357 }
358 }
359 });
360 self.plugin_registry = plugins;
361 state
362 }
363 state => state,
364 }
365 }
366
367 pub fn finish(&mut self) {
369 let plugins = std::mem::take(&mut self.plugin_registry);
370 self.run_as_app(|app| {
371 for plugin in &plugins {
372 plugin.finish(app);
373 }
374 });
375 self.plugin_registry = plugins;
376 self.plugins_state = PluginsState::Finished;
377 }
378
379 pub fn cleanup(&mut self) {
381 let plugins = std::mem::take(&mut self.plugin_registry);
382 self.run_as_app(|app| {
383 for plugin in &plugins {
384 plugin.cleanup(app);
385 }
386 });
387 self.plugin_registry = plugins;
388 self.plugins_state = PluginsState::Cleaned;
389 }
390
391 #[cfg(feature = "bevy_reflect")]
393 pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
394 let registry = self.world.resource_mut::<AppTypeRegistry>();
395 registry.write().register::<T>();
396 self
397 }
398
399 #[cfg(feature = "bevy_reflect")]
401 pub fn register_type_data<
402 T: bevy_reflect::Reflect + bevy_reflect::TypePath,
403 D: bevy_reflect::TypeData + bevy_reflect::FromType<T>,
404 >(
405 &mut self,
406 ) -> &mut Self {
407 let registry = self.world.resource_mut::<AppTypeRegistry>();
408 registry.write().register_type_data::<T, D>();
409 self
410 }
411}
412
413#[derive(Default)]
415pub struct SubApps {
416 pub main: SubApp,
418 pub sub_apps: HashMap<InternedAppLabel, SubApp>,
420}
421
422impl SubApps {
423 pub fn update(&mut self) {
426 #[cfg(feature = "trace")]
427 let _bevy_update_span = info_span!("update").entered();
428 {
429 #[cfg(feature = "trace")]
430 let _bevy_frame_update_span = info_span!("main app").entered();
431 self.main.run_default_schedule();
432 }
433 for (_label, sub_app) in self.sub_apps.iter_mut() {
434 #[cfg(feature = "trace")]
435 let _sub_app_span = info_span!("sub app", name = ?_label).entered();
436 sub_app.extract(&mut self.main.world);
437 sub_app.update();
438 }
439
440 self.main.world.clear_trackers();
441 }
442
443 pub fn iter(&self) -> impl Iterator<Item = &SubApp> + '_ {
445 std::iter::once(&self.main).chain(self.sub_apps.values())
446 }
447
448 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut SubApp> + '_ {
450 std::iter::once(&mut self.main).chain(self.sub_apps.values_mut())
451 }
452
453 pub fn update_subapp_by_label(&mut self, label: impl AppLabel) {
455 if let Some(sub_app) = self.sub_apps.get_mut(&label.intern()) {
456 sub_app.extract(&mut self.main.world);
457 sub_app.update();
458 }
459 }
460}