Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_scene/src/resolved_scene.rs
30635 views
1
use crate::{ResolveContext, ResolveSceneError, Scene, SceneList, ScenePatch};
2
use bevy_asset::{AssetId, AssetPath, AssetServer, Assets, Handle, UntypedAssetId};
3
use bevy_ecs::{
4
bundle::{Bundle, BundleScratch, BundleWriter},
5
component::{Component, ComponentsRegistrator},
6
entity::Entity,
7
error::{BevyError, Result},
8
relationship::{Relationship, RelationshipTarget},
9
template::{SceneEntityReference, SceneEntityReferences, Template, TemplateContext},
10
world::{EntityWorldMut, World},
11
};
12
use bevy_platform::collections::HashSet;
13
use bevy_utils::TypeIdMap;
14
use core::any::{Any, TypeId};
15
use thiserror::Error;
16
17
/// A final "spawnable" root [`ResolvedScene`].
18
pub struct ResolvedSceneRoot {
19
/// The root [`ResolvedScene`].
20
pub scene: ResolvedScene,
21
}
22
23
impl ResolvedSceneRoot {
24
/// Resolves the current `scene` (using [`Scene::resolve`]). This should only be called after every dependency has loaded from the `scene`'s
25
/// [`Scene::register_dependencies`].
26
pub fn resolve(
27
scene: Box<dyn Scene>,
28
assets: &AssetServer,
29
patches: &Assets<ScenePatch>,
30
) -> Result<Self, ResolveSceneError> {
31
let mut resolved_scene = ResolvedScene::default();
32
scene.resolve_box(
33
&mut ResolveContext {
34
assets,
35
patches,
36
cached: None,
37
},
38
&mut resolved_scene,
39
)?;
40
Ok(ResolvedSceneRoot {
41
scene: resolved_scene,
42
})
43
}
44
45
/// This will spawn a new [`Entity`], then call [`ResolvedSceneRoot::apply`] on it.
46
/// If this fails mid-spawn, the intermediate entity will be despawned.
47
pub fn spawn<'w>(&self, world: &'w mut World) -> Result<EntityWorldMut<'w>, ApplySceneError> {
48
let mut entity = world.spawn_empty();
49
let result = self.apply(&mut entity, &mut BundleScratch::default());
50
match result {
51
Ok(_) => Ok(entity),
52
Err(err) => {
53
entity.despawn();
54
Err(err)
55
}
56
}
57
}
58
59
/// Applies this scene to the given [`EntityWorldMut`].
60
///
61
/// This will apply all of the [`Template`]s in this root [`ResolvedScene`] to the entity. It will also
62
/// spawn all of this [`ResolvedScene`]'s related entities.
63
///
64
/// If this root [`ResolvedScene`] includes a cached scene, that scene will be applied _first_.
65
pub fn apply(
66
&self,
67
entity: &mut EntityWorldMut,
68
bundle_scratch: &mut BundleScratch,
69
) -> Result<(), ApplySceneError> {
70
let mut entity_references = SceneEntityReferences::default();
71
let mut context = TemplateContext::new(entity, &mut entity_references);
72
73
let result = self.scene.apply(&mut context, bundle_scratch);
74
if !bundle_scratch.is_empty() {
75
// SAFETY: Components comes from the same world as the `context` passed in to self.scene.apply above
76
unsafe {
77
bundle_scratch.manual_drop(entity.world().components());
78
}
79
}
80
result
81
}
82
}
83
84
/// A final "spawnable" root list of [`ResolvedScene`]s.
85
pub struct ResolvedSceneListRoot {
86
/// The root [`ResolvedScene`] list.
87
pub scenes: Vec<ResolvedScene>,
88
}
89
90
impl ResolvedSceneListRoot {
91
/// Resolves the current `scene_list` (using [`SceneList::resolve_list`]). This should only be
92
/// called after every dependency has loaded from the `scene_list`'s [`SceneList::register_dependencies`].
93
pub fn resolve(
94
scene_list: Box<dyn SceneList>,
95
assets: &AssetServer,
96
patches: &Assets<ScenePatch>,
97
) -> Result<Self, ResolveSceneError> {
98
let mut resolved_scenes = Vec::new();
99
scene_list.resolve_list_box(
100
&mut ResolveContext {
101
assets,
102
patches,
103
cached: None,
104
},
105
&mut resolved_scenes,
106
)?;
107
Ok(ResolvedSceneListRoot {
108
scenes: resolved_scenes,
109
})
110
}
111
/// Spawns a new [`Entity`] for each [`ResolvedScene`] in the list, and applies that [`ResolvedScene`] to them.
112
pub fn spawn<'w>(&self, world: &'w mut World) -> Result<Vec<Entity>, ApplySceneError> {
113
self.spawn_with(world, |_| {})
114
}
115
116
pub(crate) fn spawn_with(
117
&self,
118
world: &mut World,
119
func: impl Fn(&mut EntityWorldMut),
120
) -> Result<Vec<Entity>, ApplySceneError> {
121
let mut entities = Vec::new();
122
let mut entity_references = SceneEntityReferences::default();
123
let mut bundle_scratch = BundleScratch::default();
124
for scene in self.scenes.iter() {
125
let mut entity = if let Some(entity_index) = scene.entity_references.first().copied() {
126
let entity = entity_references.get(entity_index, world);
127
world.entity_mut(entity)
128
} else {
129
world.spawn_empty()
130
};
131
132
func(&mut entity);
133
entities.push(entity.id());
134
let result = scene.apply(
135
&mut TemplateContext::new(&mut entity, &mut entity_references),
136
&mut bundle_scratch,
137
);
138
if let Err(err) = result {
139
// SAFETY: Components comes from the same world as the `context` passed in to self.scene.apply above
140
unsafe {
141
bundle_scratch.manual_drop(entity.world().components());
142
}
143
return Err(err);
144
}
145
}
146
147
Ok(entities)
148
}
149
}
150
151
/// A final resolved scene (usually produced by calling [`Scene::resolve`]). This consists of:
152
/// 1. A collection of [`Template`]s to apply to a spawned [`Entity`], which are stored as [`ErasedComponentTemplate`]s and [`ErasedBundleTemplate`]s.
153
/// 2. A collection of [`RelatedResolvedScenes`], which will be spawned as "related" entities (ex: [`Children`] entities).
154
/// 3. An optional cached [`ScenePatch`].
155
///
156
/// This uses "copy-on-write" behavior for cached scenes. If a [`Template`] is requested which the cached scene has as well,
157
/// it will be cloned (using [`Template::clone_template`]) and added to the current [`ResolvedScene`].
158
///
159
/// When applying this [`ResolvedScene`] to an [`Entity`], the cached scene (including its related scenes) is applied _first_. _Then_ this
160
/// [`ResolvedScene`] is applied.
161
///
162
/// [`Scene::resolve`]: crate::Scene::resolve
163
/// [`Children`]: bevy_ecs::hierarchy::Children
164
#[derive(Default)]
165
pub struct ResolvedScene {
166
/// The collection of component [`Template`]s to apply to a spawned [`Entity`]. This can have multiple copies of the same [`Template`].
167
component_templates: Vec<Box<dyn ErasedComponentTemplate>>,
168
/// The collection of Bundle templates to apply to a spawned [`Entity`].
169
bundle_templates: Vec<Box<dyn ErasedBundleTemplate>>,
170
/// The collection of [`RelatedResolvedScenes`], which will be spawned as "related" entities (ex: [`Children`] entities).
171
///
172
/// [`Children`]: bevy_ecs::hierarchy::Children
173
// PERF: special casing Children might make sense here to avoid hashing
174
related: TypeIdMap<RelatedResolvedScenes>,
175
/// The cached [`ScenePatch`] to apply _first_ before applying this [`ResolvedScene`].
176
cached: Option<CachedSceneInfo>,
177
/// A [`TypeId`] to `templates` index mapping. If a [`Template`] is intended to be shared / patched across scenes, it should be registered
178
/// here.
179
template_indices: TypeIdMap<usize>,
180
/// A list of all [`SceneEntityReference`] values associated with this entity. There can be more than one if this scene uses
181
/// "flattened" caching.
182
pub entity_references: Vec<SceneEntityReference>,
183
}
184
185
impl core::fmt::Debug for ResolvedScene {
186
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187
f.debug_struct("ResolvedScene")
188
.field("cached", &self.cached)
189
.field("template_types", &self.template_indices.keys())
190
.field("related", &self.related)
191
.field("entity_references", &self.entity_references)
192
.finish()
193
}
194
}
195
196
impl ResolvedScene {
197
/// Applies this scene to the given [`TemplateContext`] (which holds an already-spawned [`EntityWorldMut`]).
198
///
199
/// This will apply all of the [`Template`]s in this [`ResolvedScene`] to the entity in the [`TemplateContext`]. It will also
200
/// spawn all of this [`ResolvedScene`]'s related entities.
201
///
202
/// If this [`ResolvedScene`] includes a cached scene, that scene will be applied _first_.
203
fn apply(
204
&self,
205
context: &mut TemplateContext,
206
bundle_scratch: &mut BundleScratch,
207
) -> Result<(), ApplySceneError> {
208
self.apply_with(context, bundle_scratch, |_, _| {})
209
}
210
211
/// Applies this scene to the given [`TemplateContext`] (which holds an already-spawned [`EntityWorldMut`]).
212
///
213
/// This will apply all of the [`Template`]s in this [`ResolvedScene`] to the entity in the [`TemplateContext`]. It will also
214
/// spawn all of this [`ResolvedScene`]'s related entities.
215
///
216
/// If this [`ResolvedScene`] includes a cached scene, that scene will be applied _first_.
217
///
218
/// This will call `writer_ops` right before calling [`BundleWriter::write`]. This will pass in the `context` value,
219
/// which is the same context used to write all of the scene components to the [`BundleWriter`]. This ensures that
220
/// writing to [`BundleWriter`] with the [`TemplateContext`] is safe (although those functions, if they are called, are still
221
/// unsafe functions / the caller should verify they are using the passed in `context`).
222
fn apply_with(
223
&self,
224
context: &mut TemplateContext,
225
bundle_scratch: &mut BundleScratch,
226
writer_ops: impl FnOnce(&mut TemplateContext, &mut BundleWriter),
227
) -> Result<(), ApplySceneError> {
228
let mut bundle_writer = bundle_scratch.writer();
229
if let Some(entity_reference) = self.entity_references.first().copied() {
230
context
231
.entity_references
232
.set(entity_reference, context.entity.id());
233
}
234
if let Some(cached) = &self.cached {
235
let scene_patches = context.resource::<Assets<ScenePatch>>();
236
let Some(patch) = scene_patches.get(&cached.handle) else {
237
return Err(ApplySceneError::MissingCachedScene {
238
path: cached.handle.path().cloned(),
239
id: cached.handle.id(),
240
});
241
};
242
let Some(resolved_cached) = &patch.resolved else {
243
return Err(ApplySceneError::UnresolvedCachedScene {
244
path: cached.handle.path().cloned(),
245
id: cached.handle.id(),
246
});
247
};
248
let resolved_cached = resolved_cached.clone();
249
// SAFETY: bundle_writer is used with the same World across all template.apply calls,
250
// and the next bundle_writer.write call
251
unsafe {
252
resolved_cached
253
.scene
254
.apply_templates_without_bundle_write(
255
context,
256
&mut bundle_writer,
257
// this will skip building / inserting templates that
258
// have local copies in the current scene
259
// (cached templates are copy-on-write)()
260
&cached.duplicate_templates,
261
)
262
.map_err(|e| ApplySceneError::CachedSceneApplyError {
263
cached: cached.handle.path().cloned(),
264
error: Box::new(e),
265
})?;
266
self.apply_templates_without_bundle_write(context, &mut bundle_writer, ())?;
267
// SAFETY: World is only used for component registration, which does not affect
268
// the entity location
269
let components = &mut context.entity.world_mut().components_registrator();
270
// This inserts empty RelationshipTarget collections to avoid archetype moves when then related entities are spawned
271
// It pre-allocates space in the collection to avoid reallocs as related entities are added.
272
for related in self.related.values() {
273
(related.insert_relationship_target)(
274
&mut bundle_writer,
275
components,
276
related.scenes.len(),
277
);
278
}
279
280
(writer_ops)(context, &mut bundle_writer);
281
282
bundle_writer.write(context.entity);
283
284
resolved_cached
285
.scene
286
.apply_related(context, bundle_scratch)?;
287
self.apply_related(context, bundle_scratch)?;
288
}
289
} else {
290
// SAFETY: bundle_writer was used with the same World across all cases in this function,
291
unsafe {
292
self.apply_templates_without_bundle_write(context, &mut bundle_writer, ())?;
293
// SAFETY: World is only used for component registration, which does not affect
294
// the entity location
295
let components = &mut context.entity.world_mut().components_registrator();
296
// This inserts empty RelationshipTarget collections to avoid archetype moves when then related entities are spawned
297
// It pre-allocates space in the collection to avoid reallocs as related entities are added.
298
for related in self.related.values() {
299
(related.insert_relationship_target)(
300
&mut bundle_writer,
301
components,
302
related.scenes.len(),
303
);
304
}
305
(writer_ops)(context, &mut bundle_writer);
306
bundle_writer.write(context.entity);
307
self.apply_related(context, bundle_scratch)?;
308
}
309
};
310
311
Ok(())
312
}
313
314
/// # Safety
315
///
316
/// `bundle_writer` must either be empty or only contain components registered with the given
317
/// `context`'s World.
318
unsafe fn apply_templates_without_bundle_write(
319
&self,
320
context: &mut TemplateContext,
321
bundle_writer: &mut BundleWriter,
322
skip_templates: impl SkipTemplate,
323
) -> Result<(), ApplySceneError> {
324
for template in &self.component_templates {
325
if skip_templates.should_skip((**template).type_id()) {
326
continue;
327
}
328
// SAFETY: bundle_writer is used with the same World across all template.apply calls,
329
// and the next bundle_writer.write call
330
unsafe {
331
template
332
.apply(context, bundle_writer)
333
.map_err(ApplySceneError::TemplateBuildError)?;
334
}
335
}
336
337
for template in &self.bundle_templates {
338
// SAFETY: bundle_writer is used with the same World across all template.apply calls,
339
// and the next bundle_writer.write call
340
unsafe {
341
template
342
.apply(context)
343
.map_err(ApplySceneError::TemplateBuildError)?;
344
}
345
}
346
Ok(())
347
}
348
349
fn apply_related(
350
&self,
351
context: &mut TemplateContext,
352
bundle_scratch: &mut BundleScratch,
353
) -> Result<(), ApplySceneError> {
354
for related_resolved_scenes in self.related.values() {
355
let target = context.entity.id();
356
let TemplateContext {
357
entity,
358
entity_references,
359
} = context;
360
entity.world_scope(|world| -> Result<(), ApplySceneError> {
361
for (index, scene) in related_resolved_scenes.scenes.iter().enumerate() {
362
let mut entity =
363
if let Some(entity_reference) = scene.entity_references.first().copied() {
364
let entity = entity_references.get(entity_reference, world);
365
world.entity_mut(entity)
366
} else {
367
world.spawn_empty()
368
};
369
370
scene
371
.apply_with(
372
&mut TemplateContext::new(&mut entity, entity_references),
373
bundle_scratch,
374
|context, bundle_writer| {
375
// SAFETY: `context` is used to write all previous `bundle_writer` components
376
// and is also used to write this relationship component
377
unsafe {
378
(related_resolved_scenes.insert_relationship)(
379
bundle_writer,
380
// SAFETY: World is only used for component registration, which does not affect
381
// the entity location
382
&mut context.entity.world_mut().components_registrator(),
383
target,
384
);
385
}
386
},
387
)
388
.map_err(|e| ApplySceneError::RelatedSceneError {
389
relationship_type_name: related_resolved_scenes.relationship_name,
390
index,
391
error: Box::new(e),
392
})?;
393
}
394
Ok(())
395
})?;
396
}
397
398
Ok(())
399
}
400
401
/// This will get the [`Template`], if it already exists in this [`ResolvedScene`]. If it doesn't exist,
402
/// it will use [`Default`] to create a new [`Template`].
403
///
404
/// This uses "copy-on-write" behavior for cached scenes. If a [`Template`] is requested which the cached scene has as well,
405
/// it will be cloned (using [`Template::clone_template`]), added to the current [`ResolvedScene`], and returned.
406
///
407
/// This will ignore [`Template`]s added to this scene using [`ResolvedScene::push_template`], as these are not registered as the "canonical"
408
/// [`Template`] for a given [`TypeId`].
409
pub fn get_or_insert_template<
410
'a,
411
T: Template<Output: Component> + Default + Send + Sync + 'static,
412
>(
413
&'a mut self,
414
context: &mut ResolveContext,
415
) -> &'a mut T {
416
(self.get_or_insert_erased_template(context, TypeId::of::<T>(), || Box::new(T::default()))
417
as &mut dyn Any)
418
// PERF: this could be unchecked, given that we control what is stored here
419
// The method isn't stable yet, and it would require making get_or_insert_erased_template unsafe
420
.downcast_mut()
421
.unwrap()
422
}
423
424
/// This will get the [`ErasedComponentTemplate`] for the given [`TypeId`], if it already exists in this [`ResolvedScene`]. If it doesn't exist,
425
/// it will use the `default` function to create a new [`ErasedComponentTemplate`]. _For correctness, the [`TypeId`] of the [`Template`] returned
426
/// by `default` should match the passed in `type_id`_.
427
///
428
/// This uses "copy-on-write" behavior for cached scenes. If a [`Template`] is requested which the cached scene has as well,
429
/// it will be cloned (using [`Template::clone_template`]), added to the current [`ResolvedScene`], and returned.
430
///
431
/// This will ignore [`Template`]s added to this scene using [`ResolvedScene::push_template`], as these are not registered as the "canonical"
432
/// [`Template`] for a given [`TypeId`].
433
pub fn get_or_insert_erased_template<'a>(
434
&'a mut self,
435
context: &mut ResolveContext,
436
type_id: TypeId,
437
default: fn() -> Box<dyn ErasedComponentTemplate>,
438
) -> &'a mut dyn ErasedComponentTemplate {
439
let mut is_cached = false;
440
let index = self.template_indices.entry(type_id).or_insert_with(|| {
441
let index = self.component_templates.len();
442
let value = if let Some(cached_patch) = &mut context.cached
443
&& let Some(resolved_cached) = &cached_patch.resolved
444
&& let Some(cached_template) =
445
resolved_cached.scene.get_direct_erased_template(type_id)
446
{
447
is_cached = true;
448
cached_template.clone_template()
449
} else {
450
default()
451
};
452
self.component_templates.push(value);
453
index
454
});
455
let template = self
456
.component_templates
457
.get_mut(*index)
458
.map(|value| &mut **value)
459
.unwrap();
460
461
if is_cached {
462
self.cached
463
.as_mut()
464
.unwrap()
465
.duplicate_templates
466
.insert(type_id);
467
}
468
469
template
470
}
471
472
/// Returns the [`ErasedComponentTemplate`] for the given `type_id`, if it exists in this [`ResolvedScene`]. This ignores cached scenes.
473
pub fn get_direct_erased_template(
474
&self,
475
type_id: TypeId,
476
) -> Option<&dyn ErasedComponentTemplate> {
477
let index = self.template_indices.get(&type_id)?;
478
Some(&*self.component_templates[*index])
479
}
480
481
/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).
482
pub fn push_template<T: Template<Output: Component> + Send + Sync + 'static>(
483
&mut self,
484
template: T,
485
) {
486
self.push_template_erased(Box::new(template));
487
}
488
489
/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).
490
pub fn push_template_erased(&mut self, template: Box<dyn ErasedComponentTemplate>) {
491
self.component_templates.push(template);
492
}
493
494
/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).
495
pub fn push_bundle_template<T: Template<Output: Bundle> + Send + Sync + 'static>(
496
&mut self,
497
template: T,
498
) {
499
self.push_bundle_template_erased(Box::new(template));
500
}
501
502
/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).
503
pub fn push_bundle_template_erased(&mut self, template: Box<dyn ErasedBundleTemplate>) {
504
self.bundle_templates.push(template);
505
}
506
/// This will return the existing [`RelatedResolvedScenes`], if it exists. If not, a new empty [`RelatedResolvedScenes`] will be inserted and returned.
507
///
508
/// This is used to add new related scenes and read existing related scenes.
509
pub fn get_or_insert_related_resolved_scenes<R: Relationship>(
510
&mut self,
511
) -> &mut RelatedResolvedScenes {
512
self.related
513
.entry(TypeId::of::<R>())
514
.or_insert_with(RelatedResolvedScenes::new::<R>)
515
}
516
517
/// Configures this [`ResolvedScene`] to include the given [`ScenePatch`] cached.
518
///
519
/// If this [`ResolvedScene`] already includes a cached scene, it will return [`CachedSceneError::MultipleCached`].
520
/// If this [`ResolvedScene`] already has [`Template`]s or related scenes, it will return [`CachedSceneError::LateCached`].
521
pub fn include_cached(&mut self, handle: Handle<ScenePatch>) -> Result<(), CachedSceneError> {
522
if let Some(cached) = &self.cached {
523
return Err(CachedSceneError::MultipleCached {
524
id: cached.handle.id().untyped(),
525
path: cached.handle.path().cloned(),
526
});
527
}
528
if !(self.component_templates.is_empty() && self.related.is_empty()) {
529
return Err(CachedSceneError::LateCached {
530
id: handle.id().untyped(),
531
path: handle.path().cloned(),
532
});
533
}
534
self.cached = Some(CachedSceneInfo {
535
handle,
536
duplicate_templates: HashSet::default(),
537
});
538
Ok(())
539
}
540
}
541
542
/// Information about a [`ResolvedScene`]'s cached scene.
543
#[derive(Debug)]
544
pub(crate) struct CachedSceneInfo {
545
/// The handle of the cached scene.
546
pub(crate) handle: Handle<ScenePatch>,
547
/// Template types that occur in _both_ the current scene and its cached scene.
548
/// This is used to skip insertion of these types when applying the cached
549
/// resolved scene.
550
pub(crate) duplicate_templates: HashSet<TypeId>,
551
}
552
553
/// The error returned by [`ResolvedScene::include_cached`].
554
#[derive(Error, Debug)]
555
pub enum CachedSceneError {
556
/// Caused when attempting to include a second cached scene.
557
#[error(
558
"Attempted to include a second cached scene (id {id:?}, path: {path:?}), which is not allowed."
559
)]
560
MultipleCached {
561
/// The asset id of the second cached scene.
562
id: UntypedAssetId,
563
/// The path of the second cached scene.
564
path: Option<AssetPath<'static>>,
565
},
566
/// Caused when attempting to include a cached scene when a [`ResolvedScene`] already has [`Template`]s or related scenes.
567
#[error("Attempted to include cached scene (id {id:?}, path: {path:?}), but the resolved scene already has templates. For correctness, the cached scene should always be included first.")]
568
LateCached {
569
/// The asset id of the cached scene that was included late.
570
id: UntypedAssetId,
571
/// The path of the cached scene that was included late.
572
path: Option<AssetPath<'static>>,
573
},
574
}
575
576
/// An error produced when applying a [`ResolvedScene`].
577
#[derive(Error, Debug)]
578
pub enum ApplySceneError {
579
/// Caused when a [`Template`] fails to build
580
#[error("Failed to build a Template in the current Scene: {0}")]
581
TemplateBuildError(BevyError),
582
/// Caused when the cached [`ResolvedScene`] fails to apply a [`ResolvedScene`].
583
#[error("Failed to apply the cached Scene (asset path: \"{cached:?}\"): {error}")]
584
CachedSceneApplyError {
585
/// The asset path of the cached scene that failed to apply.
586
cached: Option<AssetPath<'static>>,
587
/// The error that occurred while applying the cached scene.
588
error: Box<ApplySceneError>,
589
},
590
/// Caused when an cached scene is not present.
591
#[error("The cached scene (id: {id:?}, path: \"{path:?}\") does not exist.")]
592
MissingCachedScene {
593
/// The path of the cached scene.
594
path: Option<AssetPath<'static>>,
595
/// The asset id of the cached scene.
596
id: AssetId<ScenePatch>,
597
},
598
/// Caused when an cached scene has not been resolved yet.
599
#[error("The cached scene (id: {id:?}, path: \"{path:?}\") has not been resolved yet.")]
600
UnresolvedCachedScene {
601
/// The path of the cached scene.
602
path: Option<AssetPath<'static>>,
603
/// The asset id of the cached scene.
604
id: AssetId<ScenePatch>,
605
},
606
/// Caused when a related [`ResolvedScene`] fails to apply.
607
#[error(
608
"Failed to apply the related {relationship_type_name} Scene at index {index}: {error}"
609
)]
610
RelatedSceneError {
611
/// The type name of the relationship.
612
relationship_type_name: &'static str,
613
/// The index of the related scene that failed to apply.
614
index: usize,
615
/// The error that occurred when applying the related scene.
616
error: Box<ApplySceneError>,
617
},
618
}
619
620
/// A collection of [`ResolvedScene`]s that are related to a given [`ResolvedScene`] by a [`Relationship`].
621
/// Each [`ResolvedScene`] added here will be spawned as a new [`Entity`] when the "parent" [`ResolvedScene`] is spawned.
622
pub struct RelatedResolvedScenes {
623
/// The related resolved scenes. Each entry in the list corresponds to a new related entity that will be spawned with the given scene.
624
pub scenes: Vec<ResolvedScene>,
625
/// The function that will be called to add the relationship to the spawned related scene.
626
pub insert_relationship:
627
unsafe fn(&mut BundleWriter, &mut ComponentsRegistrator, target: Entity),
628
/// The function that will be called to add the relationship target to the spawned scene with the given capacity.
629
pub insert_relationship_target: unsafe fn(&mut BundleWriter, &mut ComponentsRegistrator, usize),
630
/// The type name of the relationship. This is used for more helpful error message.
631
pub relationship_name: &'static str,
632
}
633
634
impl core::fmt::Debug for RelatedResolvedScenes {
635
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
636
f.debug_struct("ResolvedRelatedScenes")
637
.field("scenes", &self.scenes)
638
.finish()
639
}
640
}
641
642
impl RelatedResolvedScenes {
643
/// Creates a new empty [`RelatedResolvedScenes`] for the given relationship type.
644
pub fn new<R: Relationship>() -> Self {
645
Self {
646
scenes: Vec::new(),
647
insert_relationship: |bundle_writer, components_registrator, target| {
648
// SAFETY: caller ensures bundler_writer is always used with the same World
649
unsafe { bundle_writer.push_component(components_registrator, R::from(target)) };
650
},
651
insert_relationship_target: |bundle_writer, components_registrator, capacity| {
652
let relationship_target =
653
<<R as Relationship>::RelationshipTarget as RelationshipTarget>::with_capacity(
654
capacity,
655
);
656
// SAFETY: caller ensures bundler_writer is always used with the same World
657
unsafe {
658
bundle_writer.push_component(components_registrator, relationship_target);
659
};
660
},
661
relationship_name: core::any::type_name::<R>(),
662
}
663
}
664
}
665
666
/// A type-erased, object-safe, downcastable version of [`Template`] that produces a [`Component`], which will be added to the
667
/// given [`BundleWriter`].
668
pub trait ErasedComponentTemplate: Any + Send + Sync {
669
/// Applies this template to the given `entity`.
670
///
671
/// # Safety
672
///
673
/// `bundle_writer` must always be used with the same World that is stored in `context`. This
674
/// is intended to be used by a scene system in a scoped / controlled / easily verifiable context.
675
/// If you are calling it outside of that context, you are almost certainly doing something wrong!
676
unsafe fn apply(
677
&self,
678
context: &mut TemplateContext,
679
bundle_writer: &mut BundleWriter,
680
) -> Result<(), BevyError>;
681
682
/// Clones this template. See [`Clone`].
683
fn clone_template(&self) -> Box<dyn ErasedComponentTemplate>;
684
}
685
686
impl<T: Template<Output: Component> + Send + Sync + 'static> ErasedComponentTemplate for T {
687
unsafe fn apply(
688
&self,
689
context: &mut TemplateContext,
690
bundle_writer: &mut BundleWriter,
691
) -> Result<(), BevyError> {
692
let component = self.build_template(context)?;
693
// SAFETY: world_mut is only used to register components, which does not affect entity location
694
let mut components = unsafe { context.entity.world_mut().components_registrator() };
695
// SAFETY: The caller verifies that `bundle_writer` is always used with the same World.
696
unsafe { bundle_writer.push_component(&mut components, component) };
697
698
Ok(())
699
}
700
701
fn clone_template(&self) -> Box<dyn ErasedComponentTemplate> {
702
Box::new(Template::clone_template(self))
703
}
704
}
705
706
/// A type-erased, object-safe, downcastable version of [`Template`] that produces a [`Bundle`], which will be added
707
/// immediately to a given `entity`.
708
pub trait ErasedBundleTemplate: Any + Send + Sync {
709
/// Applies this template to the given `entity`.
710
///
711
/// # Safety
712
///
713
/// `bundle_writer` must always be used with the same World that is stored in `context`. This
714
/// is intended to be used by a scene system in a scoped / controlled / easily verifiable context.
715
/// If you are calling it outside of that context, you are almost certainly doing something wrong!
716
unsafe fn apply(&self, context: &mut TemplateContext) -> Result<(), BevyError>;
717
718
/// Clones this template. See [`Clone`].
719
fn clone_template(&self) -> Box<dyn ErasedBundleTemplate>;
720
}
721
722
impl<T: Template<Output: Bundle> + Send + Sync + 'static> ErasedBundleTemplate for T {
723
unsafe fn apply(&self, context: &mut TemplateContext) -> Result<(), BevyError> {
724
let bundle = self.build_template(context)?;
725
context.entity.insert(bundle);
726
Ok(())
727
}
728
729
fn clone_template(&self) -> Box<dyn ErasedBundleTemplate> {
730
Box::new(Template::clone_template(self))
731
}
732
}
733
734
/// A filter to skip the template for a given `TypeId`
735
trait SkipTemplate {
736
/// Returns true if the template with `type_id` should be skipped.
737
fn should_skip(&self, type_id: TypeId) -> bool;
738
}
739
740
impl SkipTemplate for &HashSet<TypeId> {
741
#[inline]
742
fn should_skip(&self, type_id: TypeId) -> bool {
743
self.contains(&type_id)
744
}
745
}
746
747
impl SkipTemplate for () {
748
#[inline]
749
fn should_skip(&self, _type_id: TypeId) -> bool {
750
false
751
}
752
}
753
754