From 3bf15bf1d2bb744aaa6c9386a8129e549b77a263 Mon Sep 17 00:00:00 2001 From: Niklas Eicker Date: Sat, 21 Oct 2023 03:37:26 +0200 Subject: [PATCH 1/4] Share folder handles based on the folder path and reload them when their content changes --- crates/bevy_asset/src/server/info.rs | 17 ------------ crates/bevy_asset/src/server/mod.rs | 40 +++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/crates/bevy_asset/src/server/info.rs b/crates/bevy_asset/src/server/info.rs index f41057f6221e9..b81c3feb07f70 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 160a3e4d3228c..ca6adb6ecbab4 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -462,13 +462,26 @@ impl AssetServer { /// [`RecursiveDependencyLoadState`]. #[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, @@ -503,6 +516,7 @@ impl AssetServer { }) } + let path = path.into_owned(); let server = self.clone(); IoTaskPool::get() .spawn(async move { @@ -542,8 +556,6 @@ impl AssetServer { } }) .detach(); - - handle } fn send_asset_event(&self, event: InternalAssetEvent) { @@ -805,6 +817,20 @@ pub fn handle_internal_asset_events(world: &mut World) { queue_ancestors(&path, &infos, &mut paths_to_reload); paths_to_reload.insert(path); } + AssetSourceEvent::AddedAsset(path) | AssetSourceEvent::RemovedAsset(path) => { + 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); + } + } + } _ => {} } }; From d57f1451787e3e5c134f1502792934bdd54e4061 Mon Sep 17 00:00:00 2001 From: Niklas Eicker Date: Tue, 24 Oct 2023 23:15:36 +0200 Subject: [PATCH 2/4] Extend load_folder documentation --- crates/bevy_asset/src/server/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index ca6adb6ecbab4..03c588ba0490c 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -460,6 +460,11 @@ 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 path = path.into().into_owned(); From 08cba70cf1a0b648a290fcbdf4c3b1bfec945338 Mon Sep 17 00:00:00 2001 From: Niklas Eicker Date: Wed, 25 Oct 2023 21:57:51 +0200 Subject: [PATCH 3/4] Handle more AssetSourceEvents --- crates/bevy_asset/src/server/mod.rs | 37 +++++++++++++++++++---------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index 03c588ba0490c..b205b0380705c 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; @@ -812,6 +813,20 @@ 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() { + println!("checking {current_folder:?}"); + 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 { @@ -822,19 +837,15 @@ pub fn handle_internal_asset_events(world: &mut World) { queue_ancestors(&path, &infos, &mut paths_to_reload); paths_to_reload.insert(path); } - AssetSourceEvent::AddedAsset(path) | AssetSourceEvent::RemovedAsset(path) => { - 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); - } - } + 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); } _ => {} } From 508ded6cd470a76d0bd406fbc52454dec79d0c6c Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Thu, 26 Oct 2023 15:03:27 -0700 Subject: [PATCH 4/4] Remove println --- crates/bevy_asset/src/server/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index b205b0380705c..3ec5c1e827dd3 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -816,7 +816,6 @@ 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() { - println!("checking {current_folder:?}"); current_folder = parent.to_path_buf(); let parent_asset_path = AssetPath::from(current_folder.clone()).with_source(source.clone());