diff --git a/crates/bevy_asset/src/server/info.rs b/crates/bevy_asset/src/server/info.rs index f41057f6221e9b..b81c3feb07f705 100644 --- a/crates/bevy_asset/src/server/info.rs +++ b/crates/bevy_asset/src/server/info.rs @@ -86,23 +86,6 @@ impl std::fmt::Debug for AssetInfos { } impl AssetInfos { - pub(crate) fn create_loading_handle(&mut self) -> Handle { - unwrap_with_context( - Self::create_handle_internal( - &mut self.infos, - &self.handle_providers, - &mut self.living_labeled_assets, - self.watching_for_changes, - TypeId::of::(), - None, - None, - true, - ), - std::any::type_name::(), - ) - .typed_debug_checked() - } - pub(crate) fn create_loading_handle_untyped( &mut self, type_id: TypeId, diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index 73e73c25c8f930..864faf70fc71be 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -23,6 +23,7 @@ use crossbeam_channel::{Receiver, Sender}; use futures_lite::StreamExt; use info::*; use parking_lot::RwLock; +use std::path::PathBuf; use std::{any::TypeId, path::Path, sync::Arc}; use thiserror::Error; @@ -525,15 +526,33 @@ impl AssetServer { /// Loads all assets from the specified folder recursively. The [`LoadedFolder`] asset (when it loads) will /// contain handles to all assets in the folder. You can wait for all assets to load by checking the [`LoadedFolder`]'s /// [`RecursiveDependencyLoadState`]. + /// + /// Loading the same folder multiple times will return the same handle. If the `file_watcher` + /// feature is enabled, [`LoadedFolder`] handles will reload when a file in the folder is + /// removed, added or moved. This includes files in subdirectories and moving, adding, + /// or removing complete subdirectories. #[must_use = "not using the returned strong handle may result in the unexpected release of the assets"] pub fn load_folder<'a>(&self, path: impl Into>) -> Handle { - let handle = { - let mut infos = self.data.infos.write(); - infos.create_loading_handle::() - }; - let id = handle.id().untyped(); let path = path.into().into_owned(); + let (handle, should_load) = self + .data + .infos + .write() + .get_or_create_path_handle::( + path.clone(), + HandleLoadingMode::Request, + None, + ); + if !should_load { + return handle; + } + let id = handle.id().untyped(); + self.load_folder_internal(id, path); + + handle + } + pub(crate) fn load_folder_internal(&self, id: UntypedAssetId, path: AssetPath) { fn load_folder<'a>( source: AssetSourceId<'static>, path: &'a Path, @@ -568,6 +587,7 @@ impl AssetServer { }) } + let path = path.into_owned(); let server = self.clone(); IoTaskPool::get() .spawn(async move { @@ -607,8 +627,6 @@ impl AssetServer { } }) .detach(); - - handle } fn send_asset_event(&self, event: InternalAssetEvent) { @@ -860,6 +878,19 @@ pub fn handle_internal_asset_events(world: &mut World) { } } + let reload_parent_folders = |path: PathBuf, source: &AssetSourceId<'static>| { + let mut current_folder = path; + while let Some(parent) = current_folder.parent() { + current_folder = parent.to_path_buf(); + let parent_asset_path = + AssetPath::from(current_folder.clone()).with_source(source.clone()); + if let Some(folder_handle) = infos.get_path_handle(parent_asset_path.clone()) { + info!("Reloading folder {parent_asset_path} because the content has changed"); + server.load_folder_internal(folder_handle.id(), parent_asset_path); + } + } + }; + let mut paths_to_reload = HashSet::new(); let mut handle_event = |source: AssetSourceId<'static>, event: AssetSourceEvent| { match event { @@ -870,6 +901,16 @@ pub fn handle_internal_asset_events(world: &mut World) { queue_ancestors(&path, &infos, &mut paths_to_reload); paths_to_reload.insert(path); } + AssetSourceEvent::RenamedFolder { old, new } => { + reload_parent_folders(old, &source); + reload_parent_folders(new, &source); + } + AssetSourceEvent::AddedAsset(path) + | AssetSourceEvent::RemovedAsset(path) + | AssetSourceEvent::RemovedFolder(path) + | AssetSourceEvent::AddedFolder(path) => { + reload_parent_folders(path, &source); + } _ => {} } };