 01649f13e2
			
		
	
	
		01649f13e2
		
			
		
	
	
	
	
		
			
			# Objective This is a necessary precursor to #9122 (this was split from that PR to reduce the amount of code to review all at once). Moving `!Send` resource ownership to `App` will make it unambiguously `!Send`. `SubApp` must be `Send`, so it can't wrap `App`. ## Solution Refactor `App` and `SubApp` to not have a recursive relationship. Since `SubApp` no longer wraps `App`, once `!Send` resources are moved out of `World` and into `App`, `SubApp` will become unambiguously `Send`. There could be less code duplication between `App` and `SubApp`, but that would break `App` method chaining. ## Changelog - `SubApp` no longer wraps `App`. - `App` fields are no longer publicly accessible. - `App` can no longer be converted into a `SubApp`. - Various methods now return references to a `SubApp` instead of an `App`. ## Migration Guide - To construct a sub-app, use `SubApp::new()`. `App` can no longer convert into `SubApp`. - If you implemented a trait for `App`, you may want to implement it for `SubApp` as well. - If you're accessing `app.world` directly, you now have to use `app.world()` and `app.world_mut()`. - `App::sub_app` now returns `&SubApp`. - `App::sub_app_mut` now returns `&mut SubApp`. - `App::get_sub_app` now returns `Option<&SubApp>.` - `App::get_sub_app_mut` now returns `Option<&mut SubApp>.`
		
			
				
	
	
		
			100 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| #![cfg_attr(docsrs, feature(doc_auto_cfg))]
 | |
| #![forbid(unsafe_code)]
 | |
| #![doc(
 | |
|     html_logo_url = "https://bevyengine.org/assets/icon.png",
 | |
|     html_favicon_url = "https://bevyengine.org/assets/icon.png"
 | |
| )]
 | |
| 
 | |
| //! Provides scene definition, instantiation and serialization/deserialization.
 | |
| //!
 | |
| //! Scenes are collections of entities and their associated components that can be
 | |
| //! instantiated or removed from a world to allow composition. Scenes can be serialized/deserialized,
 | |
| //! for example to save part of the world state to a file.
 | |
| 
 | |
| mod bundle;
 | |
| mod dynamic_scene;
 | |
| mod dynamic_scene_builder;
 | |
| mod scene;
 | |
| mod scene_filter;
 | |
| mod scene_loader;
 | |
| mod scene_spawner;
 | |
| 
 | |
| #[cfg(feature = "serialize")]
 | |
| pub mod serde;
 | |
| 
 | |
| /// Rusty Object Notation, a crate used to serialize and deserialize bevy scenes.
 | |
| pub use bevy_asset::ron;
 | |
| 
 | |
| use bevy_ecs::schedule::IntoSystemConfigs;
 | |
| pub use bundle::*;
 | |
| pub use dynamic_scene::*;
 | |
| pub use dynamic_scene_builder::*;
 | |
| pub use scene::*;
 | |
| pub use scene_filter::*;
 | |
| pub use scene_loader::*;
 | |
| pub use scene_spawner::*;
 | |
| 
 | |
| #[allow(missing_docs)]
 | |
| pub mod prelude {
 | |
|     #[doc(hidden)]
 | |
|     pub use crate::{
 | |
|         DynamicScene, DynamicSceneBuilder, DynamicSceneBundle, Scene, SceneBundle, SceneFilter,
 | |
|         SceneSpawner,
 | |
|     };
 | |
| }
 | |
| 
 | |
| use bevy_app::prelude::*;
 | |
| use bevy_asset::{AssetApp, Handle};
 | |
| 
 | |
| /// Plugin that provides scene functionality to an [`App`].
 | |
| #[derive(Default)]
 | |
| pub struct ScenePlugin;
 | |
| 
 | |
| #[cfg(feature = "serialize")]
 | |
| impl Plugin for ScenePlugin {
 | |
|     fn build(&self, app: &mut App) {
 | |
|         app.init_asset::<DynamicScene>()
 | |
|             .init_asset::<Scene>()
 | |
|             .init_asset_loader::<SceneLoader>()
 | |
|             .add_event::<SceneInstanceReady>()
 | |
|             .init_resource::<SceneSpawner>()
 | |
|             .add_systems(SpawnScene, (scene_spawner, scene_spawner_system).chain());
 | |
| 
 | |
|         // Register component hooks for DynamicScene
 | |
|         app.world_mut()
 | |
|             .register_component_hooks::<Handle<DynamicScene>>()
 | |
|             .on_remove(|mut world, entity, _| {
 | |
|                 let Some(handle) = world.get::<Handle<DynamicScene>>(entity) else {
 | |
|                     return;
 | |
|                 };
 | |
|                 let id = handle.id();
 | |
|                 if let Some(&SceneInstance(scene_instance)) = world.get::<SceneInstance>(entity) {
 | |
|                     let Some(mut scene_spawner) = world.get_resource_mut::<SceneSpawner>() else {
 | |
|                         return;
 | |
|                     };
 | |
|                     if let Some(instance_ids) = scene_spawner.spawned_dynamic_scenes.get_mut(&id) {
 | |
|                         instance_ids.remove(&scene_instance);
 | |
|                     }
 | |
|                     scene_spawner.despawn_instance(scene_instance);
 | |
|                 }
 | |
|             });
 | |
| 
 | |
|         // Register component hooks for Scene
 | |
|         app.world_mut()
 | |
|             .register_component_hooks::<Handle<Scene>>()
 | |
|             .on_remove(|mut world, entity, _| {
 | |
|                 if let Some(&SceneInstance(scene_instance)) = world.get::<SceneInstance>(entity) {
 | |
|                     let Some(mut scene_spawner) = world.get_resource_mut::<SceneSpawner>() else {
 | |
|                         return;
 | |
|                     };
 | |
|                     scene_spawner.despawn_instance(scene_instance);
 | |
|                 }
 | |
|             });
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(not(feature = "serialize"))]
 | |
| impl Plugin for ScenePlugin {
 | |
|     fn build(&self, _: &mut App) {}
 | |
| }
 |