From 453b337d98f2f26f21ff3144cb05b9b05b39a8d1 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:37:33 -0400 Subject: [PATCH 1/9] Delay asset hot reloading for 200ms --- crates/bevy_asset/src/io/file_asset_io.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/crates/bevy_asset/src/io/file_asset_io.rs b/crates/bevy_asset/src/io/file_asset_io.rs index 867b9ed4d0852..2803822d99178 100644 --- a/crates/bevy_asset/src/io/file_asset_io.rs +++ b/crates/bevy_asset/src/io/file_asset_io.rs @@ -3,10 +3,10 @@ use crate::{filesystem_watcher::FilesystemWatcher, AssetServer}; use crate::{AssetIo, AssetIoError, Metadata}; use anyhow::Result; #[cfg(feature = "filesystem_watcher")] -use bevy_ecs::system::Res; +use bevy_ecs::system::{Local, Res}; use bevy_utils::BoxedFuture; #[cfg(feature = "filesystem_watcher")] -use bevy_utils::{default, HashSet}; +use bevy_utils::{default, Duration, HashMap, Instant}; #[cfg(feature = "filesystem_watcher")] use crossbeam_channel::TryRecvError; use fs::File; @@ -174,7 +174,10 @@ impl AssetIo for FileAssetIo { feature = "filesystem_watcher", all(not(target_arch = "wasm32"), not(target_os = "android")) ))] -pub fn filesystem_watcher_system(asset_server: Res) { +pub fn filesystem_watcher_system( + asset_server: Res, + mut changed: Local>, +) { let asset_io = if let Some(asset_io) = asset_server.server.asset_io.downcast_ref::() { asset_io @@ -182,14 +185,15 @@ pub fn filesystem_watcher_system(asset_server: Res) { return; }; let watcher = asset_io.filesystem_watcher.read(); + if let Some(ref watcher) = *watcher { - let mut changed = HashSet::<&PathBuf>::default(); loop { let event = match watcher.receiver.try_recv() { Ok(result) => result.unwrap(), Err(TryRecvError::Empty) => break, Err(TryRecvError::Disconnected) => panic!("FilesystemWatcher disconnected."), }; + if let notify::event::Event { kind: notify::event::EventKind::Modify(_), paths, @@ -199,13 +203,16 @@ pub fn filesystem_watcher_system(asset_server: Res) { for path in &paths { let Some(set) = watcher.path_map.get(path) else {continue}; for to_reload in set { - if !changed.contains(to_reload) { - changed.insert(to_reload); - let _ = asset_server.load_untracked(to_reload.as_path().into(), true); - } + changed.insert(to_reload.to_owned(), Instant::now()); } } } + + for (to_reload, _) in changed.drain_filter(|_, last_modified| { + last_modified.elapsed() >= Duration::from_millis(200) + }) { + let _ = asset_server.load_untracked(to_reload.as_path().into(), true); + } } } } From c3de03ab649d2f77cbb985ed44983fb670669a81 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:42:47 -0400 Subject: [PATCH 2/9] Cleanup --- crates/bevy_asset/src/io/file_asset_io.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_asset/src/io/file_asset_io.rs b/crates/bevy_asset/src/io/file_asset_io.rs index 2803822d99178..1326a630ea149 100644 --- a/crates/bevy_asset/src/io/file_asset_io.rs +++ b/crates/bevy_asset/src/io/file_asset_io.rs @@ -3,7 +3,7 @@ use crate::{filesystem_watcher::FilesystemWatcher, AssetServer}; use crate::{AssetIo, AssetIoError, Metadata}; use anyhow::Result; #[cfg(feature = "filesystem_watcher")] -use bevy_ecs::system::{Local, Res}; +use bevy_ecs::system::Res; use bevy_utils::BoxedFuture; #[cfg(feature = "filesystem_watcher")] use bevy_utils::{default, Duration, HashMap, Instant}; @@ -174,10 +174,7 @@ impl AssetIo for FileAssetIo { feature = "filesystem_watcher", all(not(target_arch = "wasm32"), not(target_os = "android")) ))] -pub fn filesystem_watcher_system( - asset_server: Res, - mut changed: Local>, -) { +pub fn filesystem_watcher_system(asset_server: Res) { let asset_io = if let Some(asset_io) = asset_server.server.asset_io.downcast_ref::() { asset_io @@ -187,6 +184,7 @@ pub fn filesystem_watcher_system( let watcher = asset_io.filesystem_watcher.read(); if let Some(ref watcher) = *watcher { + let mut changed = HashMap::new(); loop { let event = match watcher.receiver.try_recv() { Ok(result) => result.unwrap(), @@ -203,11 +201,13 @@ pub fn filesystem_watcher_system( for path in &paths { let Some(set) = watcher.path_map.get(path) else {continue}; for to_reload in set { + // When an asset is modified, note down the timestamp changed.insert(to_reload.to_owned(), Instant::now()); } } } + // Reload all assets whose last modification was at least 200ms ago for (to_reload, _) in changed.drain_filter(|_, last_modified| { last_modified.elapsed() >= Duration::from_millis(200) }) { From 1912022ef3bffb8eb2b4837670684025aeb5744c Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:54:03 -0400 Subject: [PATCH 3/9] Fixes --- crates/bevy_asset/src/io/file_asset_io.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/crates/bevy_asset/src/io/file_asset_io.rs b/crates/bevy_asset/src/io/file_asset_io.rs index 1326a630ea149..778a70b92ac8a 100644 --- a/crates/bevy_asset/src/io/file_asset_io.rs +++ b/crates/bevy_asset/src/io/file_asset_io.rs @@ -3,7 +3,7 @@ use crate::{filesystem_watcher::FilesystemWatcher, AssetServer}; use crate::{AssetIo, AssetIoError, Metadata}; use anyhow::Result; #[cfg(feature = "filesystem_watcher")] -use bevy_ecs::system::Res; +use bevy_ecs::system::{Res, Local}; use bevy_utils::BoxedFuture; #[cfg(feature = "filesystem_watcher")] use bevy_utils::{default, Duration, HashMap, Instant}; @@ -174,7 +174,10 @@ impl AssetIo for FileAssetIo { feature = "filesystem_watcher", all(not(target_arch = "wasm32"), not(target_os = "android")) ))] -pub fn filesystem_watcher_system(asset_server: Res) { +pub fn filesystem_watcher_system( + asset_server: Res, + mut changed: Local>, +) { let asset_io = if let Some(asset_io) = asset_server.server.asset_io.downcast_ref::() { asset_io @@ -184,7 +187,6 @@ pub fn filesystem_watcher_system(asset_server: Res) { let watcher = asset_io.filesystem_watcher.read(); if let Some(ref watcher) = *watcher { - let mut changed = HashMap::new(); loop { let event = match watcher.receiver.try_recv() { Ok(result) => result.unwrap(), @@ -206,13 +208,13 @@ pub fn filesystem_watcher_system(asset_server: Res) { } } } + } - // Reload all assets whose last modification was at least 200ms ago - for (to_reload, _) in changed.drain_filter(|_, last_modified| { - last_modified.elapsed() >= Duration::from_millis(200) - }) { - let _ = asset_server.load_untracked(to_reload.as_path().into(), true); - } + // Reload all assets whose last modification was at least 50ms ago + for (to_reload, _) in changed.drain_filter(|_, last_modified| { + last_modified.elapsed() >= Duration::from_millis(50) + }) { + let _ = asset_server.load_untracked(to_reload.as_path().into(), true); } } } From 6c2344e9cf2707f737cc3c229ecf4d1e6c29b002 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 26 Apr 2023 16:59:43 -0400 Subject: [PATCH 4/9] Improve docs --- crates/bevy_asset/src/io/file_asset_io.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/bevy_asset/src/io/file_asset_io.rs b/crates/bevy_asset/src/io/file_asset_io.rs index 778a70b92ac8a..7c9d41b4c9371 100644 --- a/crates/bevy_asset/src/io/file_asset_io.rs +++ b/crates/bevy_asset/src/io/file_asset_io.rs @@ -203,14 +203,18 @@ pub fn filesystem_watcher_system( for path in &paths { let Some(set) = watcher.path_map.get(path) else {continue}; for to_reload in set { - // When an asset is modified, note down the timestamp + // When an asset is modified, note down the timestamp (overriding any previous modification events) changed.insert(to_reload.to_owned(), Instant::now()); } } } } - // Reload all assets whose last modification was at least 50ms ago + // Reload all assets whose last modification was at least 50ms ago. + // + // When changing and then saving a shader, several modification events are sent in short succession. + // Unless we wait until we are sure the shader is finished being modified (and that there will be no more events coming), + // we will sometimes get a crash when trying to reload a partially-modified shader. for (to_reload, _) in changed.drain_filter(|_, last_modified| { last_modified.elapsed() >= Duration::from_millis(50) }) { From 6678998e4176d9d55c7322fdf39fbcacf600adc8 Mon Sep 17 00:00:00 2001 From: JMS55 <47158642+JMS55@users.noreply.github.com> Date: Wed, 26 Apr 2023 17:15:24 -0400 Subject: [PATCH 5/9] Cargo fmt --- crates/bevy_asset/src/io/file_asset_io.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_asset/src/io/file_asset_io.rs b/crates/bevy_asset/src/io/file_asset_io.rs index 7c9d41b4c9371..acbd8f302302c 100644 --- a/crates/bevy_asset/src/io/file_asset_io.rs +++ b/crates/bevy_asset/src/io/file_asset_io.rs @@ -3,7 +3,7 @@ use crate::{filesystem_watcher::FilesystemWatcher, AssetServer}; use crate::{AssetIo, AssetIoError, Metadata}; use anyhow::Result; #[cfg(feature = "filesystem_watcher")] -use bevy_ecs::system::{Res, Local}; +use bevy_ecs::system::{Local, Res}; use bevy_utils::BoxedFuture; #[cfg(feature = "filesystem_watcher")] use bevy_utils::{default, Duration, HashMap, Instant}; @@ -215,9 +215,9 @@ pub fn filesystem_watcher_system( // When changing and then saving a shader, several modification events are sent in short succession. // Unless we wait until we are sure the shader is finished being modified (and that there will be no more events coming), // we will sometimes get a crash when trying to reload a partially-modified shader. - for (to_reload, _) in changed.drain_filter(|_, last_modified| { - last_modified.elapsed() >= Duration::from_millis(50) - }) { + for (to_reload, _) in changed + .drain_filter(|_, last_modified| last_modified.elapsed() >= Duration::from_millis(50)) + { let _ = asset_server.load_untracked(to_reload.as_path().into(), true); } } From 40216510bb5826f67fa856dab0d908bd964e7eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Mon, 1 May 2023 23:38:55 +0200 Subject: [PATCH 6/9] enable configuration for the delay --- crates/bevy_asset/src/asset_server.rs | 2 +- crates/bevy_asset/src/debug_asset_server.rs | 7 +++-- crates/bevy_asset/src/filesystem_watcher.rs | 12 ++++---- crates/bevy_asset/src/io/android_asset_io.rs | 2 +- crates/bevy_asset/src/io/file_asset_io.rs | 18 ++++++------ crates/bevy_asset/src/io/mod.rs | 4 ++- crates/bevy_asset/src/io/wasm_asset_io.rs | 2 +- crates/bevy_asset/src/lib.rs | 31 ++++++++++++++++++-- examples/asset/custom_asset_io.rs | 6 ++-- examples/asset/hot_asset_reloading.rs | 4 +-- examples/scene/scene.rs | 4 +-- examples/shader/post_processing.rs | 4 ++- examples/tools/scene_viewer/main.rs | 4 ++- 13 files changed, 67 insertions(+), 33 deletions(-) diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index de6108ffab796..291e82f5462da 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -702,7 +702,7 @@ mod test { fn setup(asset_path: impl AsRef) -> AssetServer { use crate::FileAssetIo; IoTaskPool::init(Default::default); - AssetServer::new(FileAssetIo::new(asset_path, false)) + AssetServer::new(FileAssetIo::new(asset_path, &None)) } #[test] diff --git a/crates/bevy_asset/src/debug_asset_server.rs b/crates/bevy_asset/src/debug_asset_server.rs index 955fadb80f0ac..93595020ec9a0 100644 --- a/crates/bevy_asset/src/debug_asset_server.rs +++ b/crates/bevy_asset/src/debug_asset_server.rs @@ -5,14 +5,15 @@ use bevy_app::{App, Plugin, Update}; use bevy_ecs::{prelude::*, system::SystemState}; use bevy_tasks::{IoTaskPool, TaskPoolBuilder}; -use bevy_utils::HashMap; +use bevy_utils::{Duration, HashMap}; use std::{ ops::{Deref, DerefMut}, path::Path, }; use crate::{ - Asset, AssetEvent, AssetPlugin, AssetServer, Assets, FileAssetIo, Handle, HandleUntyped, + Asset, AssetEvent, AssetPlugin, AssetServer, Assets, ChangeWatcher, FileAssetIo, Handle, + HandleUntyped, }; /// A helper [`App`] used for hot reloading internal assets, which are compiled-in to Bevy plugins. @@ -72,7 +73,7 @@ impl Plugin for DebugAssetServerPlugin { let mut debug_asset_app = App::new(); debug_asset_app.add_plugin(AssetPlugin { asset_folder: "crates".to_string(), - watch_for_changes: true, + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), }); app.insert_non_send_resource(DebugAssetApp(debug_asset_app)); app.add_systems(Update, run_debug_asset_app); diff --git a/crates/bevy_asset/src/filesystem_watcher.rs b/crates/bevy_asset/src/filesystem_watcher.rs index e91dc651457a3..fa1b9c173e89b 100644 --- a/crates/bevy_asset/src/filesystem_watcher.rs +++ b/crates/bevy_asset/src/filesystem_watcher.rs @@ -1,8 +1,10 @@ -use bevy_utils::{default, HashMap, HashSet}; +use bevy_utils::{default, Duration, HashMap, HashSet}; use crossbeam_channel::Receiver; use notify::{Event, RecommendedWatcher, RecursiveMode, Result, Watcher}; use std::path::{Path, PathBuf}; +use crate::ChangeWatcher; + /// Watches for changes to files on the local filesystem. /// /// When hot-reloading is enabled, the [`AssetServer`](crate::AssetServer) uses this to reload @@ -11,10 +13,11 @@ pub struct FilesystemWatcher { pub watcher: RecommendedWatcher, pub receiver: Receiver>, pub path_map: HashMap>, + pub delay: Duration, } -impl Default for FilesystemWatcher { - fn default() -> Self { +impl FilesystemWatcher { + pub fn new(configuration: &ChangeWatcher) -> Self { let (sender, receiver) = crossbeam_channel::unbounded(); let watcher: RecommendedWatcher = RecommendedWatcher::new( move |res| { @@ -27,11 +30,10 @@ impl Default for FilesystemWatcher { watcher, receiver, path_map: default(), + delay: configuration.delay, } } -} -impl FilesystemWatcher { /// Watch for changes recursively at the provided path. pub fn watch>(&mut self, to_watch: P, to_reload: PathBuf) -> Result<()> { self.path_map diff --git a/crates/bevy_asset/src/io/android_asset_io.rs b/crates/bevy_asset/src/io/android_asset_io.rs index 4da0b6d5f100e..6119cdc491748 100644 --- a/crates/bevy_asset/src/io/android_asset_io.rs +++ b/crates/bevy_asset/src/io/android_asset_io.rs @@ -59,7 +59,7 @@ impl AssetIo for AndroidAssetIo { Ok(()) } - fn watch_for_changes(&self) -> Result<(), AssetIoError> { + fn watch_for_changes(&self, configuration: &ChangeWatcher) -> Result<(), AssetIoError> { bevy_log::warn!("Watching for changes is not supported on Android"); Ok(()) } diff --git a/crates/bevy_asset/src/io/file_asset_io.rs b/crates/bevy_asset/src/io/file_asset_io.rs index acbd8f302302c..74f01725b6280 100644 --- a/crates/bevy_asset/src/io/file_asset_io.rs +++ b/crates/bevy_asset/src/io/file_asset_io.rs @@ -1,12 +1,12 @@ #[cfg(feature = "filesystem_watcher")] use crate::{filesystem_watcher::FilesystemWatcher, AssetServer}; -use crate::{AssetIo, AssetIoError, Metadata}; +use crate::{AssetIo, AssetIoError, ChangeWatcher, Metadata}; use anyhow::Result; #[cfg(feature = "filesystem_watcher")] use bevy_ecs::system::{Local, Res}; use bevy_utils::BoxedFuture; #[cfg(feature = "filesystem_watcher")] -use bevy_utils::{default, Duration, HashMap, Instant}; +use bevy_utils::{default, HashMap, Instant}; #[cfg(feature = "filesystem_watcher")] use crossbeam_channel::TryRecvError; use fs::File; @@ -35,13 +35,13 @@ impl FileAssetIo { /// watching for changes. /// /// See `get_base_path` below. - pub fn new>(path: P, watch_for_changes: bool) -> Self { + pub fn new>(path: P, watch_for_changes: &Option) -> Self { let file_asset_io = FileAssetIo { #[cfg(feature = "filesystem_watcher")] filesystem_watcher: default(), root_path: Self::get_base_path().join(path.as_ref()), }; - if watch_for_changes { + if let Some(configuration) = watch_for_changes { #[cfg(any( not(feature = "filesystem_watcher"), target_arch = "wasm32", @@ -52,7 +52,7 @@ impl FileAssetIo { wasm32 / android targets" ); #[cfg(feature = "filesystem_watcher")] - file_asset_io.watch_for_changes().unwrap(); + file_asset_io.watch_for_changes(configuration).unwrap(); } file_asset_io } @@ -143,10 +143,10 @@ impl AssetIo for FileAssetIo { Ok(()) } - fn watch_for_changes(&self) -> Result<(), AssetIoError> { + fn watch_for_changes(&self, configuration: &ChangeWatcher) -> Result<(), AssetIoError> { #[cfg(feature = "filesystem_watcher")] { - *self.filesystem_watcher.write() = Some(default()); + *self.filesystem_watcher.write() = Some(FilesystemWatcher::new(configuration)); } #[cfg(not(feature = "filesystem_watcher"))] bevy_log::warn!("Watching for changes is not supported when the `filesystem_watcher` feature is disabled"); @@ -215,8 +215,8 @@ pub fn filesystem_watcher_system( // When changing and then saving a shader, several modification events are sent in short succession. // Unless we wait until we are sure the shader is finished being modified (and that there will be no more events coming), // we will sometimes get a crash when trying to reload a partially-modified shader. - for (to_reload, _) in changed - .drain_filter(|_, last_modified| last_modified.elapsed() >= Duration::from_millis(50)) + for (to_reload, _) in + changed.drain_filter(|_, last_modified| last_modified.elapsed() >= watcher.delay) { let _ = asset_server.load_untracked(to_reload.as_path().into(), true); } diff --git a/crates/bevy_asset/src/io/mod.rs b/crates/bevy_asset/src/io/mod.rs index 5a11e887dc2a3..081076f4ed8d1 100644 --- a/crates/bevy_asset/src/io/mod.rs +++ b/crates/bevy_asset/src/io/mod.rs @@ -25,6 +25,8 @@ use std::{ }; use thiserror::Error; +use crate::ChangeWatcher; + /// Errors that occur while loading assets. #[derive(Error, Debug)] pub enum AssetIoError { @@ -81,7 +83,7 @@ pub trait AssetIo: Downcast + Send + Sync + 'static { ) -> Result<(), AssetIoError>; /// Enables change tracking in this asset I/O. - fn watch_for_changes(&self) -> Result<(), AssetIoError>; + fn watch_for_changes(&self, configuration: &ChangeWatcher) -> Result<(), AssetIoError>; /// Returns `true` if the path is a directory. fn is_dir(&self, path: &Path) -> bool { diff --git a/crates/bevy_asset/src/io/wasm_asset_io.rs b/crates/bevy_asset/src/io/wasm_asset_io.rs index ce70fe295ae2b..6f8771ed07e59 100644 --- a/crates/bevy_asset/src/io/wasm_asset_io.rs +++ b/crates/bevy_asset/src/io/wasm_asset_io.rs @@ -64,7 +64,7 @@ impl AssetIo for WasmAssetIo { Ok(()) } - fn watch_for_changes(&self) -> Result<(), AssetIoError> { + fn watch_for_changes(&self, configuration: &ChangeWatcher) -> Result<(), AssetIoError> { bevy_log::warn!("Watching for changes is not supported in WASM"); Ok(()) } diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index 1fa2f7d59fb22..9da5265ffbbd6 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -49,6 +49,7 @@ pub use reflect::*; use bevy_app::{prelude::*, MainScheduleOrder}; use bevy_ecs::schedule::ScheduleLabel; +use bevy_utils::Duration; /// Asset storages are updated. #[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)] @@ -57,6 +58,30 @@ pub struct LoadAssets; #[derive(Debug, Hash, PartialEq, Eq, Clone, ScheduleLabel)] pub struct AssetEvents; +/// Configuration for hot reloading assets by watching for changes. +#[derive(Debug, Clone)] +pub struct ChangeWatcher { + /// Minimum delay after which a file change will trigger a reload. + /// + /// The change watcher will wait for this duration after a file change before reloading the + /// asset. This is useful to avoid reloading an asset multiple times when it is changed + /// multiple times in a short period of time, or to avoid reloading an asset that is still + /// being written to. + /// + /// If you have a slow hard drive or expect to reload large assets, you may want to increase + /// this value. + pub delay: Duration, +} + +impl ChangeWatcher { + /// Enable change watching with the given delay when a file is changed. + /// + /// See [`Self::delay`] for more details on how this value is used. + pub fn with_delay(delay: Duration) -> Option { + Some(Self { delay }) + } +} + /// Adds support for [`Assets`] to an App. /// /// Assets are typed collections with change tracking, which are added as App Resources. Examples of @@ -67,14 +92,14 @@ pub struct AssetPlugin { pub asset_folder: String, /// Whether to watch for changes in asset files. Requires the `filesystem_watcher` feature, /// and cannot be supported on the wasm32 arch nor android os. - pub watch_for_changes: bool, + pub watch_for_changes: Option, } impl Default for AssetPlugin { fn default() -> Self { Self { asset_folder: "assets".to_string(), - watch_for_changes: false, + watch_for_changes: None, } } } @@ -86,7 +111,7 @@ impl AssetPlugin { /// delegate to the default `AssetIo` for the platform. pub fn create_platform_default_asset_io(&self) -> Box { #[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))] - let source = FileAssetIo::new(&self.asset_folder, self.watch_for_changes); + let source = FileAssetIo::new(&self.asset_folder, &self.watch_for_changes); #[cfg(target_arch = "wasm32")] let source = WasmAssetIo::new(&self.asset_folder); #[cfg(target_os = "android")] diff --git a/examples/asset/custom_asset_io.rs b/examples/asset/custom_asset_io.rs index 3a525e7dd282c..df73709633e60 100644 --- a/examples/asset/custom_asset_io.rs +++ b/examples/asset/custom_asset_io.rs @@ -3,7 +3,7 @@ //! It does not know anything about the asset formats, only how to talk to the underlying storage. use bevy::{ - asset::{AssetIo, AssetIoError, Metadata}, + asset::{AssetIo, AssetIoError, ChangeWatcher, Metadata}, prelude::*, utils::BoxedFuture, }; @@ -39,9 +39,9 @@ impl AssetIo for CustomAssetIo { self.0.watch_path_for_changes(to_watch, to_reload) } - fn watch_for_changes(&self) -> Result<(), AssetIoError> { + fn watch_for_changes(&self, configuration: &ChangeWatcher) -> Result<(), AssetIoError> { info!("watch_for_changes()"); - self.0.watch_for_changes() + self.0.watch_for_changes(configuration) } fn get_metadata(&self, path: &Path) -> Result { diff --git a/examples/asset/hot_asset_reloading.rs b/examples/asset/hot_asset_reloading.rs index 971fca33c3a62..8c31d8d94d0c6 100644 --- a/examples/asset/hot_asset_reloading.rs +++ b/examples/asset/hot_asset_reloading.rs @@ -2,13 +2,13 @@ //! running. This lets you immediately see the results of your changes without restarting the game. //! This example illustrates hot reloading mesh changes. -use bevy::prelude::*; +use bevy::{asset::ChangeWatcher, prelude::*, utils::Duration}; fn main() { App::new() .add_plugins(DefaultPlugins.set(AssetPlugin { // Tell the asset server to watch for asset changes on disk: - watch_for_changes: true, + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), ..default() })) .add_systems(Startup, setup) diff --git a/examples/scene/scene.rs b/examples/scene/scene.rs index 537d669e7b921..ad4dd8d3efea2 100644 --- a/examples/scene/scene.rs +++ b/examples/scene/scene.rs @@ -1,5 +1,5 @@ //! This example illustrates loading scenes from files. -use bevy::{prelude::*, tasks::IoTaskPool, utils::Duration}; +use bevy::{asset::ChangeWatcher, prelude::*, tasks::IoTaskPool, utils::Duration}; use std::{fs::File, io::Write}; fn main() { @@ -7,7 +7,7 @@ fn main() { .add_plugins(DefaultPlugins.set(AssetPlugin { // This tells the AssetServer to watch for changes to assets. // It enables our scenes to automatically reload in game when we modify their files. - watch_for_changes: true, + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), ..default() })) .register_type::() diff --git a/examples/shader/post_processing.rs b/examples/shader/post_processing.rs index 54f45e646bde6..b087879c0621f 100644 --- a/examples/shader/post_processing.rs +++ b/examples/shader/post_processing.rs @@ -6,6 +6,7 @@ //! This is a fairly low level example and assumes some familiarity with rendering concepts and wgpu. use bevy::{ + asset::ChangeWatcher, core_pipeline::{ clear_color::ClearColorConfig, core_3d, fullscreen_vertex_shader::fullscreen_shader_vertex_state, @@ -29,13 +30,14 @@ use bevy::{ view::{ExtractedView, ViewTarget}, RenderApp, }, + utils::Duration, }; fn main() { App::new() .add_plugins(DefaultPlugins.set(AssetPlugin { // Hot reloading the shader works correctly - watch_for_changes: true, + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), ..default() })) .add_plugin(PostProcessPlugin) diff --git a/examples/tools/scene_viewer/main.rs b/examples/tools/scene_viewer/main.rs index a1519fbcda2e1..1295d7d809d3c 100644 --- a/examples/tools/scene_viewer/main.rs +++ b/examples/tools/scene_viewer/main.rs @@ -6,9 +6,11 @@ //! With no arguments it will load the `FlightHelmet` glTF model from the repository assets subdirectory. use bevy::{ + asset::ChangeWatcher, math::Vec3A, prelude::*, render::primitives::{Aabb, Sphere}, + utils::Duration, window::WindowPlugin, }; @@ -36,7 +38,7 @@ fn main() { .set(AssetPlugin { asset_folder: std::env::var("CARGO_MANIFEST_DIR") .unwrap_or_else(|_| ".".to_string()), - watch_for_changes: true, + watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), }), ) .add_plugin(CameraControllerPlugin) From 4234138e1af4f234c7778f31b4a73dd8f24b4d49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Tue, 2 May 2023 01:11:33 +0200 Subject: [PATCH 7/9] update doc example --- crates/bevy_asset/src/asset_server.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 291e82f5462da..08cd8349298f7 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -82,10 +82,11 @@ pub struct AssetServerInternal { /// ``` /// # use bevy_asset::*; /// # use bevy_app::*; +/// # use bevy_utils::Duration; /// # let mut app = App::new(); /// // The asset plugin can be configured to watch for asset changes. /// app.add_plugin(AssetPlugin { -/// watch_for_changes: true, +/// watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)), /// ..Default::default() /// }); /// ``` From 878db72d5eecf4727c97ec07785fd6e441caed1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Tue, 2 May 2023 01:12:16 +0200 Subject: [PATCH 8/9] update wasm asset --- crates/bevy_asset/src/io/wasm_asset_io.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_asset/src/io/wasm_asset_io.rs b/crates/bevy_asset/src/io/wasm_asset_io.rs index 6f8771ed07e59..00afb398ea5e6 100644 --- a/crates/bevy_asset/src/io/wasm_asset_io.rs +++ b/crates/bevy_asset/src/io/wasm_asset_io.rs @@ -1,4 +1,4 @@ -use crate::{AssetIo, AssetIoError, Metadata}; +use crate::{AssetIo, AssetIoError, ChangeWatcher, Metadata}; use anyhow::Result; use bevy_utils::BoxedFuture; use js_sys::Uint8Array; @@ -64,7 +64,7 @@ impl AssetIo for WasmAssetIo { Ok(()) } - fn watch_for_changes(&self, configuration: &ChangeWatcher) -> Result<(), AssetIoError> { + fn watch_for_changes(&self, _configuration: &ChangeWatcher) -> Result<(), AssetIoError> { bevy_log::warn!("Watching for changes is not supported in WASM"); Ok(()) } From b972711b35112f3c538ca76bbd42cf96830d0e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Mon, 8 May 2023 18:45:29 +0200 Subject: [PATCH 9/9] fix android build --- crates/bevy_asset/src/io/android_asset_io.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_asset/src/io/android_asset_io.rs b/crates/bevy_asset/src/io/android_asset_io.rs index 6119cdc491748..a5e91bb8be268 100644 --- a/crates/bevy_asset/src/io/android_asset_io.rs +++ b/crates/bevy_asset/src/io/android_asset_io.rs @@ -1,4 +1,4 @@ -use crate::{AssetIo, AssetIoError, Metadata}; +use crate::{AssetIo, AssetIoError, ChangeWatcher, Metadata}; use anyhow::Result; use bevy_utils::BoxedFuture; use std::{ @@ -59,7 +59,7 @@ impl AssetIo for AndroidAssetIo { Ok(()) } - fn watch_for_changes(&self, configuration: &ChangeWatcher) -> Result<(), AssetIoError> { + fn watch_for_changes(&self, _configuration: &ChangeWatcher) -> Result<(), AssetIoError> { bevy_log::warn!("Watching for changes is not supported on Android"); Ok(()) }