Path: blob/main/crates/bevy_scene/src/resolved_scene.rs
30635 views
use crate::{ResolveContext, ResolveSceneError, Scene, SceneList, ScenePatch};1use bevy_asset::{AssetId, AssetPath, AssetServer, Assets, Handle, UntypedAssetId};2use bevy_ecs::{3bundle::{Bundle, BundleScratch, BundleWriter},4component::{Component, ComponentsRegistrator},5entity::Entity,6error::{BevyError, Result},7relationship::{Relationship, RelationshipTarget},8template::{SceneEntityReference, SceneEntityReferences, Template, TemplateContext},9world::{EntityWorldMut, World},10};11use bevy_platform::collections::HashSet;12use bevy_utils::TypeIdMap;13use core::any::{Any, TypeId};14use thiserror::Error;1516/// A final "spawnable" root [`ResolvedScene`].17pub struct ResolvedSceneRoot {18/// The root [`ResolvedScene`].19pub scene: ResolvedScene,20}2122impl ResolvedSceneRoot {23/// Resolves the current `scene` (using [`Scene::resolve`]). This should only be called after every dependency has loaded from the `scene`'s24/// [`Scene::register_dependencies`].25pub fn resolve(26scene: Box<dyn Scene>,27assets: &AssetServer,28patches: &Assets<ScenePatch>,29) -> Result<Self, ResolveSceneError> {30let mut resolved_scene = ResolvedScene::default();31scene.resolve_box(32&mut ResolveContext {33assets,34patches,35cached: None,36},37&mut resolved_scene,38)?;39Ok(ResolvedSceneRoot {40scene: resolved_scene,41})42}4344/// This will spawn a new [`Entity`], then call [`ResolvedSceneRoot::apply`] on it.45/// If this fails mid-spawn, the intermediate entity will be despawned.46pub fn spawn<'w>(&self, world: &'w mut World) -> Result<EntityWorldMut<'w>, ApplySceneError> {47let mut entity = world.spawn_empty();48let result = self.apply(&mut entity, &mut BundleScratch::default());49match result {50Ok(_) => Ok(entity),51Err(err) => {52entity.despawn();53Err(err)54}55}56}5758/// Applies this scene to the given [`EntityWorldMut`].59///60/// This will apply all of the [`Template`]s in this root [`ResolvedScene`] to the entity. It will also61/// spawn all of this [`ResolvedScene`]'s related entities.62///63/// If this root [`ResolvedScene`] includes a cached scene, that scene will be applied _first_.64pub fn apply(65&self,66entity: &mut EntityWorldMut,67bundle_scratch: &mut BundleScratch,68) -> Result<(), ApplySceneError> {69let mut entity_references = SceneEntityReferences::default();70let mut context = TemplateContext::new(entity, &mut entity_references);7172let result = self.scene.apply(&mut context, bundle_scratch);73if !bundle_scratch.is_empty() {74// SAFETY: Components comes from the same world as the `context` passed in to self.scene.apply above75unsafe {76bundle_scratch.manual_drop(entity.world().components());77}78}79result80}81}8283/// A final "spawnable" root list of [`ResolvedScene`]s.84pub struct ResolvedSceneListRoot {85/// The root [`ResolvedScene`] list.86pub scenes: Vec<ResolvedScene>,87}8889impl ResolvedSceneListRoot {90/// Resolves the current `scene_list` (using [`SceneList::resolve_list`]). This should only be91/// called after every dependency has loaded from the `scene_list`'s [`SceneList::register_dependencies`].92pub fn resolve(93scene_list: Box<dyn SceneList>,94assets: &AssetServer,95patches: &Assets<ScenePatch>,96) -> Result<Self, ResolveSceneError> {97let mut resolved_scenes = Vec::new();98scene_list.resolve_list_box(99&mut ResolveContext {100assets,101patches,102cached: None,103},104&mut resolved_scenes,105)?;106Ok(ResolvedSceneListRoot {107scenes: resolved_scenes,108})109}110/// Spawns a new [`Entity`] for each [`ResolvedScene`] in the list, and applies that [`ResolvedScene`] to them.111pub fn spawn<'w>(&self, world: &'w mut World) -> Result<Vec<Entity>, ApplySceneError> {112self.spawn_with(world, |_| {})113}114115pub(crate) fn spawn_with(116&self,117world: &mut World,118func: impl Fn(&mut EntityWorldMut),119) -> Result<Vec<Entity>, ApplySceneError> {120let mut entities = Vec::new();121let mut entity_references = SceneEntityReferences::default();122let mut bundle_scratch = BundleScratch::default();123for scene in self.scenes.iter() {124let mut entity = if let Some(entity_index) = scene.entity_references.first().copied() {125let entity = entity_references.get(entity_index, world);126world.entity_mut(entity)127} else {128world.spawn_empty()129};130131func(&mut entity);132entities.push(entity.id());133let result = scene.apply(134&mut TemplateContext::new(&mut entity, &mut entity_references),135&mut bundle_scratch,136);137if let Err(err) = result {138// SAFETY: Components comes from the same world as the `context` passed in to self.scene.apply above139unsafe {140bundle_scratch.manual_drop(entity.world().components());141}142return Err(err);143}144}145146Ok(entities)147}148}149150/// A final resolved scene (usually produced by calling [`Scene::resolve`]). This consists of:151/// 1. A collection of [`Template`]s to apply to a spawned [`Entity`], which are stored as [`ErasedComponentTemplate`]s and [`ErasedBundleTemplate`]s.152/// 2. A collection of [`RelatedResolvedScenes`], which will be spawned as "related" entities (ex: [`Children`] entities).153/// 3. An optional cached [`ScenePatch`].154///155/// This uses "copy-on-write" behavior for cached scenes. If a [`Template`] is requested which the cached scene has as well,156/// it will be cloned (using [`Template::clone_template`]) and added to the current [`ResolvedScene`].157///158/// When applying this [`ResolvedScene`] to an [`Entity`], the cached scene (including its related scenes) is applied _first_. _Then_ this159/// [`ResolvedScene`] is applied.160///161/// [`Scene::resolve`]: crate::Scene::resolve162/// [`Children`]: bevy_ecs::hierarchy::Children163#[derive(Default)]164pub struct ResolvedScene {165/// The collection of component [`Template`]s to apply to a spawned [`Entity`]. This can have multiple copies of the same [`Template`].166component_templates: Vec<Box<dyn ErasedComponentTemplate>>,167/// The collection of Bundle templates to apply to a spawned [`Entity`].168bundle_templates: Vec<Box<dyn ErasedBundleTemplate>>,169/// The collection of [`RelatedResolvedScenes`], which will be spawned as "related" entities (ex: [`Children`] entities).170///171/// [`Children`]: bevy_ecs::hierarchy::Children172// PERF: special casing Children might make sense here to avoid hashing173related: TypeIdMap<RelatedResolvedScenes>,174/// The cached [`ScenePatch`] to apply _first_ before applying this [`ResolvedScene`].175cached: Option<CachedSceneInfo>,176/// A [`TypeId`] to `templates` index mapping. If a [`Template`] is intended to be shared / patched across scenes, it should be registered177/// here.178template_indices: TypeIdMap<usize>,179/// A list of all [`SceneEntityReference`] values associated with this entity. There can be more than one if this scene uses180/// "flattened" caching.181pub entity_references: Vec<SceneEntityReference>,182}183184impl core::fmt::Debug for ResolvedScene {185fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {186f.debug_struct("ResolvedScene")187.field("cached", &self.cached)188.field("template_types", &self.template_indices.keys())189.field("related", &self.related)190.field("entity_references", &self.entity_references)191.finish()192}193}194195impl ResolvedScene {196/// Applies this scene to the given [`TemplateContext`] (which holds an already-spawned [`EntityWorldMut`]).197///198/// This will apply all of the [`Template`]s in this [`ResolvedScene`] to the entity in the [`TemplateContext`]. It will also199/// spawn all of this [`ResolvedScene`]'s related entities.200///201/// If this [`ResolvedScene`] includes a cached scene, that scene will be applied _first_.202fn apply(203&self,204context: &mut TemplateContext,205bundle_scratch: &mut BundleScratch,206) -> Result<(), ApplySceneError> {207self.apply_with(context, bundle_scratch, |_, _| {})208}209210/// Applies this scene to the given [`TemplateContext`] (which holds an already-spawned [`EntityWorldMut`]).211///212/// This will apply all of the [`Template`]s in this [`ResolvedScene`] to the entity in the [`TemplateContext`]. It will also213/// spawn all of this [`ResolvedScene`]'s related entities.214///215/// If this [`ResolvedScene`] includes a cached scene, that scene will be applied _first_.216///217/// This will call `writer_ops` right before calling [`BundleWriter::write`]. This will pass in the `context` value,218/// which is the same context used to write all of the scene components to the [`BundleWriter`]. This ensures that219/// writing to [`BundleWriter`] with the [`TemplateContext`] is safe (although those functions, if they are called, are still220/// unsafe functions / the caller should verify they are using the passed in `context`).221fn apply_with(222&self,223context: &mut TemplateContext,224bundle_scratch: &mut BundleScratch,225writer_ops: impl FnOnce(&mut TemplateContext, &mut BundleWriter),226) -> Result<(), ApplySceneError> {227let mut bundle_writer = bundle_scratch.writer();228if let Some(entity_reference) = self.entity_references.first().copied() {229context230.entity_references231.set(entity_reference, context.entity.id());232}233if let Some(cached) = &self.cached {234let scene_patches = context.resource::<Assets<ScenePatch>>();235let Some(patch) = scene_patches.get(&cached.handle) else {236return Err(ApplySceneError::MissingCachedScene {237path: cached.handle.path().cloned(),238id: cached.handle.id(),239});240};241let Some(resolved_cached) = &patch.resolved else {242return Err(ApplySceneError::UnresolvedCachedScene {243path: cached.handle.path().cloned(),244id: cached.handle.id(),245});246};247let resolved_cached = resolved_cached.clone();248// SAFETY: bundle_writer is used with the same World across all template.apply calls,249// and the next bundle_writer.write call250unsafe {251resolved_cached252.scene253.apply_templates_without_bundle_write(254context,255&mut bundle_writer,256// this will skip building / inserting templates that257// have local copies in the current scene258// (cached templates are copy-on-write)()259&cached.duplicate_templates,260)261.map_err(|e| ApplySceneError::CachedSceneApplyError {262cached: cached.handle.path().cloned(),263error: Box::new(e),264})?;265self.apply_templates_without_bundle_write(context, &mut bundle_writer, ())?;266// SAFETY: World is only used for component registration, which does not affect267// the entity location268let components = &mut context.entity.world_mut().components_registrator();269// This inserts empty RelationshipTarget collections to avoid archetype moves when then related entities are spawned270// It pre-allocates space in the collection to avoid reallocs as related entities are added.271for related in self.related.values() {272(related.insert_relationship_target)(273&mut bundle_writer,274components,275related.scenes.len(),276);277}278279(writer_ops)(context, &mut bundle_writer);280281bundle_writer.write(context.entity);282283resolved_cached284.scene285.apply_related(context, bundle_scratch)?;286self.apply_related(context, bundle_scratch)?;287}288} else {289// SAFETY: bundle_writer was used with the same World across all cases in this function,290unsafe {291self.apply_templates_without_bundle_write(context, &mut bundle_writer, ())?;292// SAFETY: World is only used for component registration, which does not affect293// the entity location294let components = &mut context.entity.world_mut().components_registrator();295// This inserts empty RelationshipTarget collections to avoid archetype moves when then related entities are spawned296// It pre-allocates space in the collection to avoid reallocs as related entities are added.297for related in self.related.values() {298(related.insert_relationship_target)(299&mut bundle_writer,300components,301related.scenes.len(),302);303}304(writer_ops)(context, &mut bundle_writer);305bundle_writer.write(context.entity);306self.apply_related(context, bundle_scratch)?;307}308};309310Ok(())311}312313/// # Safety314///315/// `bundle_writer` must either be empty or only contain components registered with the given316/// `context`'s World.317unsafe fn apply_templates_without_bundle_write(318&self,319context: &mut TemplateContext,320bundle_writer: &mut BundleWriter,321skip_templates: impl SkipTemplate,322) -> Result<(), ApplySceneError> {323for template in &self.component_templates {324if skip_templates.should_skip((**template).type_id()) {325continue;326}327// SAFETY: bundle_writer is used with the same World across all template.apply calls,328// and the next bundle_writer.write call329unsafe {330template331.apply(context, bundle_writer)332.map_err(ApplySceneError::TemplateBuildError)?;333}334}335336for template in &self.bundle_templates {337// SAFETY: bundle_writer is used with the same World across all template.apply calls,338// and the next bundle_writer.write call339unsafe {340template341.apply(context)342.map_err(ApplySceneError::TemplateBuildError)?;343}344}345Ok(())346}347348fn apply_related(349&self,350context: &mut TemplateContext,351bundle_scratch: &mut BundleScratch,352) -> Result<(), ApplySceneError> {353for related_resolved_scenes in self.related.values() {354let target = context.entity.id();355let TemplateContext {356entity,357entity_references,358} = context;359entity.world_scope(|world| -> Result<(), ApplySceneError> {360for (index, scene) in related_resolved_scenes.scenes.iter().enumerate() {361let mut entity =362if let Some(entity_reference) = scene.entity_references.first().copied() {363let entity = entity_references.get(entity_reference, world);364world.entity_mut(entity)365} else {366world.spawn_empty()367};368369scene370.apply_with(371&mut TemplateContext::new(&mut entity, entity_references),372bundle_scratch,373|context, bundle_writer| {374// SAFETY: `context` is used to write all previous `bundle_writer` components375// and is also used to write this relationship component376unsafe {377(related_resolved_scenes.insert_relationship)(378bundle_writer,379// SAFETY: World is only used for component registration, which does not affect380// the entity location381&mut context.entity.world_mut().components_registrator(),382target,383);384}385},386)387.map_err(|e| ApplySceneError::RelatedSceneError {388relationship_type_name: related_resolved_scenes.relationship_name,389index,390error: Box::new(e),391})?;392}393Ok(())394})?;395}396397Ok(())398}399400/// This will get the [`Template`], if it already exists in this [`ResolvedScene`]. If it doesn't exist,401/// it will use [`Default`] to create a new [`Template`].402///403/// This uses "copy-on-write" behavior for cached scenes. If a [`Template`] is requested which the cached scene has as well,404/// it will be cloned (using [`Template::clone_template`]), added to the current [`ResolvedScene`], and returned.405///406/// This will ignore [`Template`]s added to this scene using [`ResolvedScene::push_template`], as these are not registered as the "canonical"407/// [`Template`] for a given [`TypeId`].408pub fn get_or_insert_template<409'a,410T: Template<Output: Component> + Default + Send + Sync + 'static,411>(412&'a mut self,413context: &mut ResolveContext,414) -> &'a mut T {415(self.get_or_insert_erased_template(context, TypeId::of::<T>(), || Box::new(T::default()))416as &mut dyn Any)417// PERF: this could be unchecked, given that we control what is stored here418// The method isn't stable yet, and it would require making get_or_insert_erased_template unsafe419.downcast_mut()420.unwrap()421}422423/// This will get the [`ErasedComponentTemplate`] for the given [`TypeId`], if it already exists in this [`ResolvedScene`]. If it doesn't exist,424/// it will use the `default` function to create a new [`ErasedComponentTemplate`]. _For correctness, the [`TypeId`] of the [`Template`] returned425/// by `default` should match the passed in `type_id`_.426///427/// This uses "copy-on-write" behavior for cached scenes. If a [`Template`] is requested which the cached scene has as well,428/// it will be cloned (using [`Template::clone_template`]), added to the current [`ResolvedScene`], and returned.429///430/// This will ignore [`Template`]s added to this scene using [`ResolvedScene::push_template`], as these are not registered as the "canonical"431/// [`Template`] for a given [`TypeId`].432pub fn get_or_insert_erased_template<'a>(433&'a mut self,434context: &mut ResolveContext,435type_id: TypeId,436default: fn() -> Box<dyn ErasedComponentTemplate>,437) -> &'a mut dyn ErasedComponentTemplate {438let mut is_cached = false;439let index = self.template_indices.entry(type_id).or_insert_with(|| {440let index = self.component_templates.len();441let value = if let Some(cached_patch) = &mut context.cached442&& let Some(resolved_cached) = &cached_patch.resolved443&& let Some(cached_template) =444resolved_cached.scene.get_direct_erased_template(type_id)445{446is_cached = true;447cached_template.clone_template()448} else {449default()450};451self.component_templates.push(value);452index453});454let template = self455.component_templates456.get_mut(*index)457.map(|value| &mut **value)458.unwrap();459460if is_cached {461self.cached462.as_mut()463.unwrap()464.duplicate_templates465.insert(type_id);466}467468template469}470471/// Returns the [`ErasedComponentTemplate`] for the given `type_id`, if it exists in this [`ResolvedScene`]. This ignores cached scenes.472pub fn get_direct_erased_template(473&self,474type_id: TypeId,475) -> Option<&dyn ErasedComponentTemplate> {476let index = self.template_indices.get(&type_id)?;477Some(&*self.component_templates[*index])478}479480/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).481pub fn push_template<T: Template<Output: Component> + Send + Sync + 'static>(482&mut self,483template: T,484) {485self.push_template_erased(Box::new(template));486}487488/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).489pub fn push_template_erased(&mut self, template: Box<dyn ErasedComponentTemplate>) {490self.component_templates.push(template);491}492493/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).494pub fn push_bundle_template<T: Template<Output: Bundle> + Send + Sync + 'static>(495&mut self,496template: T,497) {498self.push_bundle_template_erased(Box::new(template));499}500501/// Adds the `template` to the "back" of the [`ResolvedScene`] (it will applied later than earlier [`Template`]s).502pub fn push_bundle_template_erased(&mut self, template: Box<dyn ErasedBundleTemplate>) {503self.bundle_templates.push(template);504}505/// This will return the existing [`RelatedResolvedScenes`], if it exists. If not, a new empty [`RelatedResolvedScenes`] will be inserted and returned.506///507/// This is used to add new related scenes and read existing related scenes.508pub fn get_or_insert_related_resolved_scenes<R: Relationship>(509&mut self,510) -> &mut RelatedResolvedScenes {511self.related512.entry(TypeId::of::<R>())513.or_insert_with(RelatedResolvedScenes::new::<R>)514}515516/// Configures this [`ResolvedScene`] to include the given [`ScenePatch`] cached.517///518/// If this [`ResolvedScene`] already includes a cached scene, it will return [`CachedSceneError::MultipleCached`].519/// If this [`ResolvedScene`] already has [`Template`]s or related scenes, it will return [`CachedSceneError::LateCached`].520pub fn include_cached(&mut self, handle: Handle<ScenePatch>) -> Result<(), CachedSceneError> {521if let Some(cached) = &self.cached {522return Err(CachedSceneError::MultipleCached {523id: cached.handle.id().untyped(),524path: cached.handle.path().cloned(),525});526}527if !(self.component_templates.is_empty() && self.related.is_empty()) {528return Err(CachedSceneError::LateCached {529id: handle.id().untyped(),530path: handle.path().cloned(),531});532}533self.cached = Some(CachedSceneInfo {534handle,535duplicate_templates: HashSet::default(),536});537Ok(())538}539}540541/// Information about a [`ResolvedScene`]'s cached scene.542#[derive(Debug)]543pub(crate) struct CachedSceneInfo {544/// The handle of the cached scene.545pub(crate) handle: Handle<ScenePatch>,546/// Template types that occur in _both_ the current scene and its cached scene.547/// This is used to skip insertion of these types when applying the cached548/// resolved scene.549pub(crate) duplicate_templates: HashSet<TypeId>,550}551552/// The error returned by [`ResolvedScene::include_cached`].553#[derive(Error, Debug)]554pub enum CachedSceneError {555/// Caused when attempting to include a second cached scene.556#[error(557"Attempted to include a second cached scene (id {id:?}, path: {path:?}), which is not allowed."558)]559MultipleCached {560/// The asset id of the second cached scene.561id: UntypedAssetId,562/// The path of the second cached scene.563path: Option<AssetPath<'static>>,564},565/// Caused when attempting to include a cached scene when a [`ResolvedScene`] already has [`Template`]s or related scenes.566#[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.")]567LateCached {568/// The asset id of the cached scene that was included late.569id: UntypedAssetId,570/// The path of the cached scene that was included late.571path: Option<AssetPath<'static>>,572},573}574575/// An error produced when applying a [`ResolvedScene`].576#[derive(Error, Debug)]577pub enum ApplySceneError {578/// Caused when a [`Template`] fails to build579#[error("Failed to build a Template in the current Scene: {0}")]580TemplateBuildError(BevyError),581/// Caused when the cached [`ResolvedScene`] fails to apply a [`ResolvedScene`].582#[error("Failed to apply the cached Scene (asset path: \"{cached:?}\"): {error}")]583CachedSceneApplyError {584/// The asset path of the cached scene that failed to apply.585cached: Option<AssetPath<'static>>,586/// The error that occurred while applying the cached scene.587error: Box<ApplySceneError>,588},589/// Caused when an cached scene is not present.590#[error("The cached scene (id: {id:?}, path: \"{path:?}\") does not exist.")]591MissingCachedScene {592/// The path of the cached scene.593path: Option<AssetPath<'static>>,594/// The asset id of the cached scene.595id: AssetId<ScenePatch>,596},597/// Caused when an cached scene has not been resolved yet.598#[error("The cached scene (id: {id:?}, path: \"{path:?}\") has not been resolved yet.")]599UnresolvedCachedScene {600/// The path of the cached scene.601path: Option<AssetPath<'static>>,602/// The asset id of the cached scene.603id: AssetId<ScenePatch>,604},605/// Caused when a related [`ResolvedScene`] fails to apply.606#[error(607"Failed to apply the related {relationship_type_name} Scene at index {index}: {error}"608)]609RelatedSceneError {610/// The type name of the relationship.611relationship_type_name: &'static str,612/// The index of the related scene that failed to apply.613index: usize,614/// The error that occurred when applying the related scene.615error: Box<ApplySceneError>,616},617}618619/// A collection of [`ResolvedScene`]s that are related to a given [`ResolvedScene`] by a [`Relationship`].620/// Each [`ResolvedScene`] added here will be spawned as a new [`Entity`] when the "parent" [`ResolvedScene`] is spawned.621pub struct RelatedResolvedScenes {622/// The related resolved scenes. Each entry in the list corresponds to a new related entity that will be spawned with the given scene.623pub scenes: Vec<ResolvedScene>,624/// The function that will be called to add the relationship to the spawned related scene.625pub insert_relationship:626unsafe fn(&mut BundleWriter, &mut ComponentsRegistrator, target: Entity),627/// The function that will be called to add the relationship target to the spawned scene with the given capacity.628pub insert_relationship_target: unsafe fn(&mut BundleWriter, &mut ComponentsRegistrator, usize),629/// The type name of the relationship. This is used for more helpful error message.630pub relationship_name: &'static str,631}632633impl core::fmt::Debug for RelatedResolvedScenes {634fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {635f.debug_struct("ResolvedRelatedScenes")636.field("scenes", &self.scenes)637.finish()638}639}640641impl RelatedResolvedScenes {642/// Creates a new empty [`RelatedResolvedScenes`] for the given relationship type.643pub fn new<R: Relationship>() -> Self {644Self {645scenes: Vec::new(),646insert_relationship: |bundle_writer, components_registrator, target| {647// SAFETY: caller ensures bundler_writer is always used with the same World648unsafe { bundle_writer.push_component(components_registrator, R::from(target)) };649},650insert_relationship_target: |bundle_writer, components_registrator, capacity| {651let relationship_target =652<<R as Relationship>::RelationshipTarget as RelationshipTarget>::with_capacity(653capacity,654);655// SAFETY: caller ensures bundler_writer is always used with the same World656unsafe {657bundle_writer.push_component(components_registrator, relationship_target);658};659},660relationship_name: core::any::type_name::<R>(),661}662}663}664665/// A type-erased, object-safe, downcastable version of [`Template`] that produces a [`Component`], which will be added to the666/// given [`BundleWriter`].667pub trait ErasedComponentTemplate: Any + Send + Sync {668/// Applies this template to the given `entity`.669///670/// # Safety671///672/// `bundle_writer` must always be used with the same World that is stored in `context`. This673/// is intended to be used by a scene system in a scoped / controlled / easily verifiable context.674/// If you are calling it outside of that context, you are almost certainly doing something wrong!675unsafe fn apply(676&self,677context: &mut TemplateContext,678bundle_writer: &mut BundleWriter,679) -> Result<(), BevyError>;680681/// Clones this template. See [`Clone`].682fn clone_template(&self) -> Box<dyn ErasedComponentTemplate>;683}684685impl<T: Template<Output: Component> + Send + Sync + 'static> ErasedComponentTemplate for T {686unsafe fn apply(687&self,688context: &mut TemplateContext,689bundle_writer: &mut BundleWriter,690) -> Result<(), BevyError> {691let component = self.build_template(context)?;692// SAFETY: world_mut is only used to register components, which does not affect entity location693let mut components = unsafe { context.entity.world_mut().components_registrator() };694// SAFETY: The caller verifies that `bundle_writer` is always used with the same World.695unsafe { bundle_writer.push_component(&mut components, component) };696697Ok(())698}699700fn clone_template(&self) -> Box<dyn ErasedComponentTemplate> {701Box::new(Template::clone_template(self))702}703}704705/// A type-erased, object-safe, downcastable version of [`Template`] that produces a [`Bundle`], which will be added706/// immediately to a given `entity`.707pub trait ErasedBundleTemplate: Any + Send + Sync {708/// Applies this template to the given `entity`.709///710/// # Safety711///712/// `bundle_writer` must always be used with the same World that is stored in `context`. This713/// is intended to be used by a scene system in a scoped / controlled / easily verifiable context.714/// If you are calling it outside of that context, you are almost certainly doing something wrong!715unsafe fn apply(&self, context: &mut TemplateContext) -> Result<(), BevyError>;716717/// Clones this template. See [`Clone`].718fn clone_template(&self) -> Box<dyn ErasedBundleTemplate>;719}720721impl<T: Template<Output: Bundle> + Send + Sync + 'static> ErasedBundleTemplate for T {722unsafe fn apply(&self, context: &mut TemplateContext) -> Result<(), BevyError> {723let bundle = self.build_template(context)?;724context.entity.insert(bundle);725Ok(())726}727728fn clone_template(&self) -> Box<dyn ErasedBundleTemplate> {729Box::new(Template::clone_template(self))730}731}732733/// A filter to skip the template for a given `TypeId`734trait SkipTemplate {735/// Returns true if the template with `type_id` should be skipped.736fn should_skip(&self, type_id: TypeId) -> bool;737}738739impl SkipTemplate for &HashSet<TypeId> {740#[inline]741fn should_skip(&self, type_id: TypeId) -> bool {742self.contains(&type_id)743}744}745746impl SkipTemplate for () {747#[inline]748fn should_skip(&self, _type_id: TypeId) -> bool {749false750}751}752753754