diff --git a/crates/bevy_scene/Cargo.toml b/crates/bevy_scene/Cargo.toml index bce74814e819b..4f5143d00949d 100644 --- a/crates/bevy_scene/Cargo.toml +++ b/crates/bevy_scene/Cargo.toml @@ -23,5 +23,6 @@ bevy_utils = { path = "../bevy_utils", version = "0.19.0-dev" } thiserror = { version = "2", default-features = false } tracing = { version = "0.1", default-features = false, features = ["std"] } variadics_please = "1.0" + [lints] workspace = true diff --git a/crates/bevy_scene/src/resolved_scene.rs b/crates/bevy_scene/src/resolved_scene.rs index 64659bd59106e..f8245fec3dd19 100644 --- a/crates/bevy_scene/src/resolved_scene.rs +++ b/crates/bevy_scene/src/resolved_scene.rs @@ -1,5 +1,5 @@ -use crate::{ResolveContext, ScenePatch}; -use bevy_asset::{AssetId, AssetPath, Assets, Handle, UntypedAssetId}; +use crate::{ResolveContext, ResolveSceneError, Scene, SceneList, ScenePatch}; +use bevy_asset::{AssetId, AssetPath, AssetServer, Assets, Handle, UntypedAssetId}; use bevy_ecs::{ bundle::{Bundle, BundleScratch, BundleWriter}, component::{Component, ComponentsRegistrator}, @@ -23,6 +23,31 @@ pub struct ResolvedSceneRoot { } impl ResolvedSceneRoot { + /// Resolves the current `scene` (using [`Scene::resolve`]). This should only be called after every dependency has loaded from the `scene`'s + /// [`Scene::register_dependencies`]. + pub fn resolve( + scene: Box, + assets: &AssetServer, + patches: &Assets, + ) -> Result { + let mut resolved_scene = ResolvedScene::default(); + let mut entity_scopes = EntityScopes::default(); + scene.resolve_box( + &mut ResolveContext { + assets, + patches, + current_scope: 0, + entity_scopes: &mut entity_scopes, + inherited: None, + }, + &mut resolved_scene, + )?; + Ok(ResolvedSceneRoot { + scene: resolved_scene, + entity_scopes, + }) + } + /// This will spawn a new [`Entity`], then call [`ResolvedSceneRoot::apply`] on it. /// If this fails mid-spawn, the intermediate entity will be despawned. pub fn spawn<'w>(&self, world: &'w mut World) -> Result, ApplySceneError> { @@ -75,6 +100,30 @@ pub struct ResolvedSceneListRoot { } impl ResolvedSceneListRoot { + /// Resolves the current `scene_list` (using [`SceneList::resolve_list`]). This should only be + /// called after every dependency has loaded from the `scene_list`'s [`SceneList::register_dependencies`]. + pub fn resolve( + scene_list: Box, + assets: &AssetServer, + patches: &Assets, + ) -> Result { + let mut resolved_scenes = Vec::new(); + let mut entity_scopes = EntityScopes::default(); + scene_list.resolve_list_box( + &mut ResolveContext { + assets, + patches, + current_scope: 0, + entity_scopes: &mut entity_scopes, + inherited: None, + }, + &mut resolved_scenes, + )?; + Ok(ResolvedSceneListRoot { + scenes: resolved_scenes, + entity_scopes, + }) + } /// Spawns a new [`Entity`] for each [`ResolvedScene`] in the list, and applies that [`ResolvedScene`] to them. pub fn spawn<'w>(&self, world: &'w mut World) -> Result, ApplySceneError> { self.spawn_with(world, |_| {}) diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index 0416b2c21fe08..11d8c3553be59 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -37,7 +37,7 @@ use variadics_please::all_tuples; /// /// See [`ResolvedScene`] for more information on how it can be composed. /// -/// A [`Scene`] can have dependencies (defined with [`Scene::register_dependencies`]), which _must_ be loaded before calling [`Scene::resolve`], or it +/// A [`Scene`] can have dependencies (defined in [`Scene::register_dependencies`]), which _must_ be loaded before calling [`Scene::resolve`], or it /// might return a [`ResolveSceneError`]. /// /// You generally don't need to resolve [`Scene`]s yourself. Instead use APIs like [`World::spawn_scene`] or [`World::queue_spawn_scene`] @@ -47,26 +47,82 @@ use variadics_please::all_tuples; /// [`World::queue_spawn_scene`]: crate::WorldSceneExt::queue_spawn_scene /// [`Entity`]: bevy_ecs::entity::Entity /// [`Component`]: bevy_ecs::component::Component -pub trait Scene: Send + Sync + 'static { +pub trait Scene: SceneBox { /// This will apply the changes described in this [`Scene`] to the given [`ResolvedScene`]. This should not be called until all of the dependencies /// in [`Scene::register_dependencies`] have been loaded. The scene system will generally call this method on behalf of developers. /// /// [`Scene`]s are free to modify [`ResolvedScene`] in arbitrary ways. In the context of related entities, in general they should just be pushing new /// entities to the back of the list. fn resolve( - &self, + self, context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError>; - /// [`Scene`] can have [`Asset`] dependencies, which _must_ be loaded before calling [`Scene::resolve`] or it might return a [`ResolveSceneError`]! + /// [`Scene`] can have [`Asset`] dependencies, which _must_ be loaded before calling [`Scene::resolve`] / [`SceneList::resolve_list`] or it might return a [`ResolveSceneError`]! /// - /// In most cases, the scene system will ensure [`Scene::resolve`] is called _after_ these dependencies have been loaded. + /// In most cases, the scene system will ensure [`Scene::resolve`] / [`SceneList::resolve_list`] is called _after_ these dependencies have been loaded. /// /// [`Asset`]: bevy_asset::Asset fn register_dependencies(&self, _dependencies: &mut SceneDependencies) {} } +/// Boxed version of [`Scene`], which enables implementing [`Scene`] for [`Box`]. Most +/// developers do not need to think about or use this trait. +/// +/// Related: [`SceneListBox`]. +/// +/// ## Why does this exist? +/// +/// [`Scene::resolve`] consumes `self`, which by default is not something that [`Box`] +/// can do in Rust, as `dyn Scene` is "unsized". The "way out" is to have every [`Scene`] type +/// _also_ know how to resolve itself for `self: Box`. [`SceneBox`] has a blanket impl +/// for `Scene + Sized` (which can just rely on the [`Scene`] impl). Then [`Box`] has a +/// manual [`SceneBox`] impl that relies on the _stored_ [`SceneBox::resolve_box`] impl. +/// +/// [`SceneListBox`]: crate::SceneListBox +pub trait SceneBox: Send + Sync + 'static { + /// See [`Scene::resolve`]. + fn resolve_box( + self: Box, + context: &mut ResolveContext, + scene: &mut ResolvedScene, + ) -> Result<(), ResolveSceneError>; + + /// See [`Scene::register_dependencies`]. + fn register_dependencies_box(&self, _dependencies: &mut SceneDependencies); +} + +impl SceneBox for S { + #[inline] + fn resolve_box( + self: Box, + context: &mut ResolveContext, + scene: &mut ResolvedScene, + ) -> Result<(), ResolveSceneError> { + (*self).resolve(context, scene) + } + + #[inline] + fn register_dependencies_box(&self, dependencies: &mut SceneDependencies) { + self.register_dependencies(dependencies); + } +} + +impl Scene for Box { + fn resolve( + self, + context: &mut ResolveContext, + scene: &mut ResolvedScene, + ) -> Result<(), ResolveSceneError> { + self.resolve_box(context, scene) + } + + fn register_dependencies(&self, dependencies: &mut SceneDependencies) { + (**self).register_dependencies_box(dependencies); + } +} + /// A collection of asset dependencies required by a [`Scene`]. #[derive(Default)] pub struct SceneDependencies(Vec); @@ -107,6 +163,9 @@ pub enum ResolveSceneError { /// Caused when inheriting a scene during [`Scene::resolve`] fails. #[error(transparent)] InheritSceneError(#[from] InheritSceneError), + /// Caused when a Scene/SceneList is not present on the scene asset. + #[error("The Scene/SceneList is not present on the scene asset. This is likely because the scene has already been resolved, which consumed the source scene")] + MissingScene, } /// Context used by [`Scene`] implementations during [`Scene::resolve`]. @@ -146,7 +205,7 @@ impl<'a> ResolveContext<'a> { macro_rules! scene_impl { ($($patch: ident),*) => { impl<$($patch: Scene),*> Scene for ($($patch,)*) { - fn resolve(&self, _context: &mut ResolveContext, _scene: &mut ResolvedScene) -> Result<(), ResolveSceneError> { + fn resolve(self, _context: &mut ResolveContext, _scene: &mut ResolvedScene) -> Result<(), ResolveSceneError> { #[expect( clippy::allow_attributes, reason = "This is inside a macro, and as such, may not trigger in all cases." @@ -178,33 +237,6 @@ macro_rules! scene_impl { all_tuples!(scene_impl, 0, 12, P); -impl Scene for Box { - fn resolve( - &self, - context: &mut ResolveContext, - scene: &mut ResolvedScene, - ) -> Result<(), ResolveSceneError> { - (**self).resolve(context, scene) - } - fn register_dependencies(&self, dependencies: &mut SceneDependencies) { - (**self).register_dependencies(dependencies); - } -} - -impl SceneList for Box { - fn resolve_list( - &self, - context: &mut ResolveContext, - scenes: &mut Vec, - ) -> Result<(), ResolveSceneError> { - (**self).resolve_list(context, scenes) - } - - fn register_dependencies(&self, dependencies: &mut SceneDependencies) { - (**self).register_dependencies(dependencies); - } -} - /// A [`Scene`] that patches a [`Template`] of type `T` with a given function `F`. /// /// Functionally, a [`TemplatePatch`] scene will initialize a [`Default`] value of the patched @@ -231,16 +263,16 @@ impl SceneList for Box { /// let position = Position { x: 0, y: 0}; /// // applying patch to position would result in { x: 10, y: 0 } /// ``` -pub struct TemplatePatch(pub F, pub PhantomData); +pub struct TemplatePatch(pub F, pub PhantomData); /// Returns a [`Scene`] that completely overwrites the current value of a [`Template`] `T` with the given `value`. /// The `value` is cloned each time the [`Template`] is built. -pub fn template_value( +pub fn template_value( value: T, -) -> TemplatePatch { +) -> TemplatePatch { TemplatePatch( move |input: &mut T, _context: &mut ResolveContext| { - *input = value.clone(); + *input = value; }, PhantomData, ) @@ -253,14 +285,14 @@ pub trait PatchFromTemplate { type Template; /// Takes a "patch function" `func`, and turns it into a [`TemplatePatch`]. - fn patch( + fn patch( func: F, ) -> TemplatePatch; } impl PatchFromTemplate for G { type Template = G::Template; - fn patch( + fn patch( func: F, ) -> TemplatePatch { TemplatePatch(func, PhantomData) @@ -270,22 +302,25 @@ impl PatchFromTemplate for G { /// A helper function that returns a [`TemplatePatch`] [`Scene`] for something that implements [`Template`]. pub trait PatchTemplate: Sized { /// Takes a "patch function" `func` that patches this [`Template`], and turns it into a [`TemplatePatch`]. - fn patch_template(func: F) -> TemplatePatch; + fn patch_template(func: F) + -> TemplatePatch; } impl PatchTemplate for T { - fn patch_template(func: F) -> TemplatePatch { + fn patch_template( + func: F, + ) -> TemplatePatch { TemplatePatch(func, PhantomData) } } impl< - F: Fn(&mut T, &mut ResolveContext) + Send + Sync + 'static, + F: FnOnce(&mut T, &mut ResolveContext) + Send + Sync + 'static, T: Template + Send + Sync + Default + 'static, > Scene for TemplatePatch { fn resolve( - &self, + self, context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError> { @@ -317,7 +352,7 @@ impl RelatedScenes { impl Scene for RelatedScenes { fn resolve( - &self, + self, context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError> { @@ -352,7 +387,7 @@ impl>> From for InheritSceneAsset { impl Scene for InheritSceneAsset { fn resolve( - &self, + self, context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError> { @@ -376,7 +411,7 @@ impl Result) + Clone + Send + Sync + 'static, for FnTemplate { fn resolve( - &self, + self, _context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError> { @@ -402,7 +437,7 @@ pub struct NameEntityReference { impl Scene for NameEntityReference { fn resolve( - &self, + self, context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError> { @@ -429,7 +464,7 @@ pub struct SceneScope(pub S); impl Scene for SceneScope { fn resolve( - &self, + self, context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError> { @@ -447,7 +482,7 @@ pub struct SceneListScope(pub L); impl SceneList for SceneListScope { fn resolve_list( - &self, + self, context: &mut ResolveContext, scenes: &mut Vec, ) -> Result<(), ResolveSceneError> { @@ -488,7 +523,7 @@ impl< > Scene for OnTemplate { fn resolve( - &self, + self, _context: &mut ResolveContext, scene: &mut ResolvedScene, ) -> Result<(), ResolveSceneError> { diff --git a/crates/bevy_scene/src/scene_list.rs b/crates/bevy_scene/src/scene_list.rs index 65a45e931a754..0e70a123c1f46 100644 --- a/crates/bevy_scene/src/scene_list.rs +++ b/crates/bevy_scene/src/scene_list.rs @@ -6,11 +6,11 @@ use variadics_please::all_tuples; /// [`Scene`] is to [`Entity`] as [`SceneList`] is to [`Vec`]. /// /// [`Entity`]: bevy_ecs::entity::Entity -pub trait SceneList: Send + Sync + 'static { +pub trait SceneList: SceneListBox { /// This will apply the changes described in this [`SceneList`] to the given [`Vec`]. This should not be called until all of /// the dependencies in [`Scene::register_dependencies`] have been loaded. fn resolve_list( - &self, + self, context: &mut ResolveContext, scenes: &mut Vec, ) -> Result<(), ResolveSceneError>; @@ -22,6 +22,63 @@ pub trait SceneList: Send + Sync + 'static { fn register_dependencies(&self, dependencies: &mut SceneDependencies); } +/// Boxed version of [`SceneList`], which enables implementing [`SceneList`] for [`Box`]. +/// Most developers do not need to think about or use this trait. +/// +/// Related: [`SceneBox`]. +/// +/// ## Why does this exist? +/// +/// [`SceneList::resolve_list`] consumes `self`, which by default is not something that +/// [`Box`] can do in Rust, as `dyn Scene` is "unsized". The "way out" is to have +/// every [`Scene`] type _also_ know how to resolve itself for `self: Box`. [`SceneListBox`] +/// has a blanket impl for `SceneList + Sized` (which can just rely on the [`SceneList`] impl). +/// Then [`Box`] has a manual [`SceneListBox`] impl that relies on the _stored_ +/// [`SceneListBox::resolve_list_box`] impl. +/// +/// [`SceneBox`]: crate::SceneBox +pub trait SceneListBox: Send + Sync + 'static { + /// See [`SceneList::resolve_list`]. + fn resolve_list_box( + self: Box, + context: &mut ResolveContext, + scenes: &mut Vec, + ) -> Result<(), ResolveSceneError>; + + /// See [`SceneList::register_dependencies`]. + fn register_dependencies_box(&self, dependencies: &mut SceneDependencies); +} + +impl SceneListBox for L { + #[inline] + fn resolve_list_box( + self: Box, + context: &mut ResolveContext, + scenes: &mut Vec, + ) -> Result<(), ResolveSceneError> { + (*self).resolve_list(context, scenes) + } + + #[inline] + fn register_dependencies_box(&self, dependencies: &mut SceneDependencies) { + self.register_dependencies(dependencies); + } +} + +impl SceneList for Box { + fn resolve_list( + self, + context: &mut ResolveContext, + scenes: &mut Vec, + ) -> Result<(), ResolveSceneError> { + self.resolve_list_box(context, scenes) + } + + fn register_dependencies(&self, dependencies: &mut SceneDependencies) { + (**self).register_dependencies_box(dependencies); + } +} + /// Corresponds to a single member of a [`SceneList`] (an [`Entity`] with an `S` [`Scene`]). /// /// [`Entity`]: bevy_ecs::entity::Entity @@ -29,7 +86,7 @@ pub struct EntityScene(pub S); impl SceneList for EntityScene { fn resolve_list( - &self, + self, context: &mut ResolveContext, scenes: &mut Vec, ) -> Result<(), ResolveSceneError> { @@ -47,7 +104,7 @@ impl SceneList for EntityScene { macro_rules! scene_list_impl { ($($list: ident),*) => { impl<$($list: SceneList),*> SceneList for ($($list,)*) { - fn resolve_list(&self, _context: &mut ResolveContext, _scenes: &mut Vec) -> Result<(), ResolveSceneError> { + fn resolve_list(self, _context: &mut ResolveContext, _scenes: &mut Vec) -> Result<(), ResolveSceneError> { #[expect( clippy::allow_attributes, reason = "This is inside a macro, and as such, may not trigger in all cases." @@ -81,7 +138,7 @@ all_tuples!(scene_list_impl, 0, 12, P); impl SceneList for Vec { fn resolve_list( - &self, + self, context: &mut ResolveContext, scenes: &mut Vec, ) -> Result<(), ResolveSceneError> { diff --git a/crates/bevy_scene/src/scene_patch.rs b/crates/bevy_scene/src/scene_patch.rs index 96c680a78f217..48491289079e0 100644 --- a/crates/bevy_scene/src/scene_patch.rs +++ b/crates/bevy_scene/src/scene_patch.rs @@ -1,6 +1,6 @@ use crate::{ - ApplySceneError, ResolveContext, ResolveSceneError, ResolvedScene, ResolvedSceneListRoot, - ResolvedSceneRoot, Scene, SceneDependencies, SceneList, + ApplySceneError, ResolveSceneError, ResolvedSceneListRoot, ResolvedSceneRoot, Scene, + SceneDependencies, SceneList, }; use alloc::sync::Arc; use bevy_asset::{Asset, AssetServer, Assets, Handle, LoadFromPath, UntypedHandle}; @@ -9,21 +9,21 @@ use bevy_ecs::{ bundle::BundleScratch, component::Component, entity::Entity, - template::{EntityScopes, FromTemplate}, + template::FromTemplate, world::{EntityWorldMut, World}, }; use bevy_reflect::TypePath; use thiserror::Error; -/// An [`Asset`] that holds a [`Scene`], tracks its dependencies, and holds the [`ResolvedScene`] (after the [`Scene`] has been loaded and resolved). +/// An [`Asset`] that holds a [`Scene`], tracks its dependencies, and holds the [`ResolvedSceneRoot`] (after the [`Scene`] has been loaded and resolved). #[derive(Asset, TypePath)] pub struct ScenePatch { /// A [`Scene`]. - pub scene: Box, + pub scene: Option>, /// The dependencies of `scene` (populated using [`Scene::register_dependencies`]). These are "asset dependencies" and will affect the load state. #[dependency] pub dependencies: Vec, - /// The [`ResolvedScene`], if exists. This is populated after the [`Scene`] has been loaded and resolved + /// The [`ResolvedSceneRoot`], if exists. This is populated after the [`Scene`] has been loaded and resolved // TODO: consider breaking this out to prevent mutating asset events when resolved. Assets as Entities will enable this! // TODO: This Arc exists to allow nested ResolvedSceneRoot::apply when borrowing inherited ScenePatch assets (see the ResolvedSceneRoot::apply implementation). pub resolved: Option>, @@ -46,7 +46,7 @@ impl ScenePatch { .map(|i| load_from_path.load_from_path_erased(i.type_id, i.path.clone())) .collect::>(); ScenePatch { - scene: Box::new(scene), + scene: Some(Box::new(scene)), dependencies, resolved: None, } @@ -59,35 +59,13 @@ impl ScenePatch { assets: &AssetServer, patches: &Assets, ) -> Result<(), ResolveSceneError> { - let resolved = self.resolve_internal(assets, patches)?; - self.resolved = Some(Arc::new(resolved)); + let scene = self.scene.take().ok_or(ResolveSceneError::MissingScene)?; + self.resolved = Some(Arc::new(ResolvedSceneRoot::resolve( + scene, assets, patches, + )?)); Ok(()) } - pub(crate) fn resolve_internal( - &self, - assets: &AssetServer, - patches: &Assets, - ) -> Result { - let mut scene = ResolvedScene::default(); - let mut entity_scopes = EntityScopes::default(); - self.scene.resolve( - &mut ResolveContext { - assets, - patches, - current_scope: 0, - entity_scopes: &mut entity_scopes, - inherited: None, - }, - &mut scene, - )?; - - Ok(ResolvedSceneRoot { - scene, - entity_scopes, - }) - } - /// Spawns the scene in `world` as a new entity. This should only be called after [`ScenePatch::resolve`]. pub fn spawn<'w>(&self, world: &'w mut World) -> Result, SpawnSceneError> { let resolved = self @@ -114,7 +92,9 @@ impl ScenePatch { /// An [`Error`] that occurs during scene spawning. #[derive(Error, Debug)] pub enum SpawnSceneError { - /// Failed to apply a [`ResolvedScene`]s. + /// Failed to apply a [`ResolvedScene`]. + /// + /// [`ResolvedScene`]: crate::ResolvedScene #[error(transparent)] ApplySceneError(#[from] ApplySceneError), #[error(transparent)] @@ -129,11 +109,11 @@ pub enum SpawnSceneError { #[derive(Component, FromTemplate, Deref, DerefMut)] pub struct ScenePatchInstance(pub Handle); -/// An [`Asset`] that holds a [`SceneList`], tracks its dependencies, and holds a [`Vec`] of [`ResolvedScene`] (after the [`SceneList`] has been loaded and resolved) +/// An [`Asset`] that holds a [`SceneList`], tracks its dependencies, and holds a [`ResolvedSceneListRoot`] (after the [`SceneList`] has been loaded and resolved) #[derive(Asset, TypePath)] pub struct SceneListPatch { /// A [`SceneList`]. - pub scene_list: Box, + pub scene_list: Option>, /// The dependencies of `scene_list` (populated using [`SceneList::register_dependencies`]). These are "asset dependencies" and will affect the load state. #[dependency] @@ -155,7 +135,7 @@ impl SceneListPatch { .map(|dep| assets.load_builder().load_erased(dep.type_id, &dep.path)) .collect::>(); SceneListPatch { - scene_list: Box::new(scene_list), + scene_list: Some(Box::new(scene_list)), dependencies, resolved: None, } @@ -168,37 +148,14 @@ impl SceneListPatch { assets: &AssetServer, patches: &Assets, ) -> Result<(), ResolveSceneError> { - let resolved = self.resolve_internal(assets, patches)?; - self.resolved = Some(resolved); + let scene_list = self + .scene_list + .take() + .ok_or(ResolveSceneError::MissingScene)?; + self.resolved = Some(ResolvedSceneListRoot::resolve(scene_list, assets, patches)?); Ok(()) } - /// Resolves the current `scene` (using [`SceneList::resolve_list`]). This should only be called after every dependency has loaded from the `scene_list`'s - /// [`SceneList::register_dependencies`]. - pub(crate) fn resolve_internal( - &self, - assets: &AssetServer, - patches: &Assets, - ) -> Result { - let mut scenes = Vec::new(); - let mut entity_scopes = EntityScopes::default(); - self.scene_list.resolve_list( - &mut ResolveContext { - assets, - patches, - current_scope: 0, - entity_scopes: &mut entity_scopes, - inherited: None, - }, - &mut scenes, - )?; - - Ok(ResolvedSceneListRoot { - scenes, - entity_scopes, - }) - } - /// Spawns the scene list in `world` as new entities. This should only be called after [`SceneListPatch::resolve`]. pub fn spawn<'w>(&self, world: &'w mut World) -> Result, SpawnSceneError> { self.spawn_with(world, |_| {}) diff --git a/crates/bevy_scene/src/spawn.rs b/crates/bevy_scene/src/spawn.rs index 9d75046779747..e3dd823275813 100644 --- a/crates/bevy_scene/src/spawn.rs +++ b/crates/bevy_scene/src/spawn.rs @@ -1,4 +1,7 @@ -use crate::{Scene, SceneList, SceneListPatch, ScenePatch, ScenePatchInstance, SpawnSceneError}; +use crate::{ + ResolvedSceneRoot, Scene, SceneList, SceneListPatch, ScenePatch, ScenePatchInstance, + SpawnSceneError, +}; use alloc::sync::Arc; use bevy_asset::{AssetEvent, AssetServer, Assets, Handle}; use bevy_ecs::{ @@ -593,8 +596,8 @@ pub fn resolve_scene_patches( for event in events.read() { match *event { AssetEvent::LoadedWithDependencies { id } => { - if let Some(patch) = patches.get(id) { - match patch.resolve_internal(&assets, &patches) { + if let Some(scene) = patches.get_mut(id).and_then(|mut p| p.scene.take()) { + match ResolvedSceneRoot::resolve(scene, &assets, &patches) { Ok(resolved) => { let mut patch = patches.get_mut(id).unwrap(); patch.resolved = Some(Arc::new(resolved)); @@ -618,13 +621,10 @@ pub fn resolve_scene_patches( for event in list_events.read() { match *event { AssetEvent::LoadedWithDependencies { id } => { - if let Some(mut list_patch) = list_patches.get_mut(id) { - match list_patch.resolve_internal(&assets, &patches) { - Ok(resolved) => { - list_patch.resolved = Some(resolved); - } - Err(err) => error!("Failed to resolve scene list {id}: {err}"), - } + if let Some(mut list_patch) = list_patches.get_mut(id) + && let Err(err) = list_patch.resolve(&assets, &patches) + { + error!("Failed to resolve scene list {id}: {err}"); } } AssetEvent::Removed { id } => {