bevy_scene/
scene_patch.rs1use crate::{
2 ApplySceneError, ResolveSceneError, ResolvedSceneListRoot, ResolvedSceneRoot, Scene,
3 SceneDependencies, SceneList,
4};
5use alloc::sync::Arc;
6use bevy_asset::{Asset, AssetServer, Assets, Handle, LoadFromPath, UntypedHandle};
7use bevy_derive::{Deref, DerefMut};
8use bevy_ecs::{
9 bundle::BundleScratch,
10 component::Component,
11 entity::Entity,
12 template::FromTemplate,
13 world::{EntityWorldMut, World},
14};
15use bevy_reflect::TypePath;
16use thiserror::Error;
17
18#[derive(Asset, TypePath)]
20pub struct ScenePatch {
21 pub scene: Option<Box<dyn Scene>>,
23 #[dependency]
25 pub dependencies: Vec<UntypedHandle>,
26 pub resolved: Option<Arc<ResolvedSceneRoot>>,
30}
31
32impl ScenePatch {
33 pub fn load<P: Scene>(mut assets: &AssetServer, scene: P) -> Self {
36 Self::load_with(&mut assets, scene)
37 }
38
39 pub fn load_with<P: Scene>(load_from_path: &mut impl LoadFromPath, scene: P) -> Self {
42 let mut dependencies = SceneDependencies::default();
43 scene.register_dependencies(&mut dependencies);
44 let dependencies = dependencies
45 .iter()
46 .map(|i| load_from_path.load_from_path_erased(i.type_id, i.path.clone()))
47 .collect::<Vec<_>>();
48 ScenePatch {
49 scene: Some(Box::new(scene)),
50 dependencies,
51 resolved: None,
52 }
53 }
54
55 pub fn resolve(
58 &mut self,
59 assets: &AssetServer,
60 patches: &Assets<ScenePatch>,
61 ) -> Result<(), ResolveSceneError> {
62 let scene = self.scene.take().ok_or(ResolveSceneError::MissingScene)?;
63 self.resolved = Some(Arc::new(ResolvedSceneRoot::resolve(
64 scene, assets, patches,
65 )?));
66 Ok(())
67 }
68
69 pub fn spawn<'w>(&self, world: &'w mut World) -> Result<EntityWorldMut<'w>, SpawnSceneError> {
71 let resolved = self
72 .resolved
73 .as_deref()
74 .ok_or(SpawnSceneError::UnresolvedSceneError)?;
75 resolved
76 .spawn(world)
77 .map_err(SpawnSceneError::ApplySceneError)
78 }
79
80 pub fn apply<'w>(&self, entity: &'w mut EntityWorldMut) -> Result<(), SpawnSceneError> {
82 let resolved = self
83 .resolved
84 .as_deref()
85 .ok_or(SpawnSceneError::UnresolvedSceneError)?;
86 resolved
87 .apply(entity, &mut BundleScratch::default())
88 .map_err(SpawnSceneError::ApplySceneError)
89 }
90}
91
92#[derive(Error, Debug)]
94pub enum SpawnSceneError {
95 #[error(transparent)]
99 ApplySceneError(#[from] ApplySceneError),
100 #[error(transparent)]
101 ResolveSceneError(#[from] ResolveSceneError),
103 #[error("This scene has not been resolved yet and cannot be spawned. It is likely waiting for dependencies to load")]
105 UnresolvedSceneError,
106}
107
108#[derive(Component, FromTemplate, Deref, DerefMut)]
110pub struct ScenePatchInstance(pub Handle<ScenePatch>);
111
112#[derive(Asset, TypePath)]
114pub struct SceneListPatch {
115 pub scene_list: Option<Box<dyn SceneList>>,
117
118 #[dependency]
120 pub dependencies: Vec<UntypedHandle>,
121
122 pub resolved: Option<ResolvedSceneListRoot>,
125}
126
127impl SceneListPatch {
128 pub fn load<L: SceneList>(assets: &AssetServer, scene_list: L) -> Self {
131 let mut dependencies = SceneDependencies::default();
132 scene_list.register_dependencies(&mut dependencies);
133 let dependencies = dependencies
134 .iter()
135 .map(|dep| assets.load_builder().load_erased(dep.type_id, &dep.path))
136 .collect::<Vec<_>>();
137 SceneListPatch {
138 scene_list: Some(Box::new(scene_list)),
139 dependencies,
140 resolved: None,
141 }
142 }
143
144 pub fn resolve(
147 &mut self,
148 assets: &AssetServer,
149 patches: &Assets<ScenePatch>,
150 ) -> Result<(), ResolveSceneError> {
151 let scene_list = self
152 .scene_list
153 .take()
154 .ok_or(ResolveSceneError::MissingScene)?;
155 self.resolved = Some(ResolvedSceneListRoot::resolve(scene_list, assets, patches)?);
156 Ok(())
157 }
158
159 pub fn spawn<'w>(&self, world: &'w mut World) -> Result<Vec<Entity>, SpawnSceneError> {
161 self.spawn_with(world, |_| {})
162 }
163
164 pub(crate) fn spawn_with<'w>(
166 &self,
167 world: &'w mut World,
168 func: impl Fn(&mut EntityWorldMut),
169 ) -> Result<Vec<Entity>, SpawnSceneError> {
170 let resolved = self
171 .resolved
172 .as_ref()
173 .ok_or(SpawnSceneError::UnresolvedSceneError)?;
174 resolved
175 .spawn_with(world, func)
176 .map_err(SpawnSceneError::ApplySceneError)
177 }
178}