Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_scene/src/scene_patch.rs
30635 views
1
use crate::{
2
ApplySceneError, ResolveSceneError, ResolvedSceneListRoot, ResolvedSceneRoot, Scene,
3
SceneDependencies, SceneList,
4
};
5
use alloc::sync::Arc;
6
use bevy_asset::{Asset, AssetServer, Assets, Handle, LoadFromPath, UntypedHandle};
7
use bevy_derive::{Deref, DerefMut};
8
use bevy_ecs::{
9
bundle::BundleScratch,
10
component::Component,
11
entity::Entity,
12
template::FromTemplate,
13
world::{EntityWorldMut, World},
14
};
15
use bevy_reflect::TypePath;
16
use thiserror::Error;
17
18
/// An [`Asset`] that holds a [`Scene`], tracks its dependencies, and holds the [`ResolvedSceneRoot`] (after the [`Scene`] has been loaded and resolved).
19
#[derive(Asset, TypePath)]
20
pub struct ScenePatch {
21
/// A [`Scene`].
22
pub scene: Option<Box<dyn Scene>>,
23
/// The dependencies of `scene` (populated using [`Scene::register_dependencies`]). These are "asset dependencies" and will affect the load state.
24
#[dependency]
25
pub dependencies: Vec<UntypedHandle>,
26
/// The [`ResolvedSceneRoot`], if exists. This is populated after the [`Scene`] has been loaded and resolved
27
// TODO: consider breaking this out to prevent mutating asset events when resolved. Assets as Entities will enable this!
28
// TODO: This Arc exists to allow nested ResolvedSceneRoot::apply when borrowing cached ScenePatch assets (see the ResolvedSceneRoot::apply implementation).
29
pub resolved: Option<Arc<ResolvedSceneRoot>>,
30
}
31
32
impl ScenePatch {
33
/// Kicks off a load of the `scene`. This enumerates the scene's dependencies using [`Scene::register_dependencies`], loads
34
/// them using the given [`AssetServer`], and assigns the resulting asset handles to [`ScenePatch::dependencies`].
35
pub fn load<P: Scene>(mut assets: &AssetServer, scene: P) -> Self {
36
Self::load_with(&mut assets, scene)
37
}
38
39
/// Same as [`Self::load`], but allows passing in any [`LoadFromPath`] impl for more general
40
/// loading cases.
41
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
/// Resolves the current `scene` (using [`Scene::resolve`]). This should only be called after every dependency has loaded from the `scene`'s
56
/// [`Scene::register_dependencies`]. If successful, it will store the resolved result in [`ScenePatch::resolved`].
57
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
/// Spawns the scene in `world` as a new entity. This should only be called after [`ScenePatch::resolve`].
70
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
/// Applies the scene to the given `entity`. This should only be called after [`ScenePatch::resolve`]
81
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
/// An [`Error`] that occurs during scene spawning.
93
#[derive(Error, Debug)]
94
pub enum SpawnSceneError {
95
/// Failed to apply a [`ResolvedScene`].
96
///
97
/// [`ResolvedScene`]: crate::ResolvedScene
98
#[error(transparent)]
99
ApplySceneError(#[from] ApplySceneError),
100
#[error(transparent)]
101
/// Calling [`Scene::resolve`] failed.
102
ResolveSceneError(#[from] ResolveSceneError),
103
/// Attempted to spawn a scene that has not been resolved yet.
104
#[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
/// A component that, when added, will queue applying the given [`ScenePatch`] after the scene and its dependencies have been loaded and resolved.
109
#[derive(Component, FromTemplate, Deref, DerefMut)]
110
pub struct ScenePatchInstance(pub Handle<ScenePatch>);
111
112
/// An [`Asset`] that holds a [`SceneList`], tracks its dependencies, and holds a [`ResolvedSceneListRoot`] (after the [`SceneList`] has been loaded and resolved)
113
#[derive(Asset, TypePath)]
114
pub struct SceneListPatch {
115
/// A [`SceneList`].
116
pub scene_list: Option<Box<dyn SceneList>>,
117
118
/// The dependencies of `scene_list` (populated using [`SceneList::register_dependencies`]). These are "asset dependencies" and will affect the load state.
119
#[dependency]
120
pub dependencies: Vec<UntypedHandle>,
121
122
/// The [`ResolvedSceneListRoot`], if exists. This is populated after the scene list and its dependencies have been loaded and resolved.
123
// TODO: consider breaking this out to prevent mutating asset events when resolved
124
pub resolved: Option<ResolvedSceneListRoot>,
125
}
126
127
impl SceneListPatch {
128
/// Kicks off a load of the `scene_list`. This enumerates the scene list's dependencies using [`SceneList::register_dependencies`], loads
129
/// them using the given [`AssetServer`], and assigns the resulting asset handles to [`SceneListPatch::dependencies`].
130
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
/// Resolves the current `scene` (using [`SceneList::resolve_list`]). This should only be called after every dependency has loaded from the `scene_list`'s
145
/// [`SceneList::register_dependencies`].
146
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
/// Spawns the scene list in `world` as new entities. This should only be called after [`SceneListPatch::resolve`].
160
pub fn spawn<'w>(&self, world: &'w mut World) -> Result<Vec<Entity>, SpawnSceneError> {
161
self.spawn_with(world, |_| {})
162
}
163
164
/// Spawns the scene list in `world` as new entities. This should only be called after [`SceneListPatch::resolve`].
165
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
}
179
180