bevy_asset: Add AssetServerSettings watch_for_changes member (#3643)

# Objective

- `asset_server.watch_for_changes().unwrap()` only watches changes for assets loaded **_after_** that call.
- Technically, the `hot_asset_reloading` example is racey as the watch on the asset path is set up in an async task scheduled from the asset `load()`, but the filesystem watcher is only constructed in a call that comes **_after_** the call to `load()`.

## Solution

-  It feels safest to allow enabling watching the filesystem for changes on the asset server from the point of its construction. Therefore, adding such an option to `AssetServerSettings` seemed to be the correct solution.
- Fix `hot_asset_reloading` by inserting the `AssetServerSettings` resource with `watch_for_changes: true` instead of calling `asset_server.watch_for_changes().unwrap()`.
- Document the shortcomings of `.watch_for_changes()`
This commit is contained in:
Robert Swain 2022-02-04 03:21:29 +00:00
parent ca83e8a6de
commit e928acb9ff
4 changed files with 30 additions and 8 deletions

View file

@ -115,6 +115,8 @@ impl AssetServer {
loaders.push(Arc::new(loader));
}
/// Enable watching of the filesystem for changes, if support is available, starting from after
/// the point of calling this function.
pub fn watch_for_changes(&self) -> Result<(), AssetServerError> {
self.server.asset_io.watch_for_changes()?;
Ok(())
@ -622,7 +624,7 @@ mod test {
handle_to_path: Default::default(),
asset_lifecycles: Default::default(),
task_pool: Default::default(),
asset_io: Box::new(FileAssetIo::new(asset_path)),
asset_io: Box::new(FileAssetIo::new(asset_path, false)),
}),
}
}

View file

@ -27,12 +27,26 @@ pub struct FileAssetIo {
}
impl FileAssetIo {
pub fn new<P: AsRef<Path>>(path: P) -> Self {
FileAssetIo {
pub fn new<P: AsRef<Path>>(path: P, watch_for_changes: bool) -> Self {
let file_asset_io = FileAssetIo {
#[cfg(feature = "filesystem_watcher")]
filesystem_watcher: Default::default(),
root_path: Self::get_root_path().join(path.as_ref()),
};
if watch_for_changes {
#[cfg(any(
not(feature = "filesystem_watcher"),
target_arch = "wasm32",
target_os = "android"
))]
panic!(
"Watch for changes requires the filesystem_watcher feature and cannot be used on \
wasm32 / android targets"
);
#[cfg(feature = "filesystem_watcher")]
file_asset_io.watch_for_changes().unwrap();
}
file_asset_io
}
pub fn get_root_path() -> PathBuf {

View file

@ -44,12 +44,16 @@ pub struct AssetPlugin;
pub struct AssetServerSettings {
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,
}
impl Default for AssetServerSettings {
fn default() -> Self {
Self {
asset_folder: "assets".to_string(),
watch_for_changes: false,
}
}
}
@ -64,7 +68,7 @@ pub fn create_platform_default_asset_io(app: &mut App) -> Box<dyn AssetIo> {
.get_resource_or_insert_with(AssetServerSettings::default);
#[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
let source = FileAssetIo::new(&settings.asset_folder);
let source = FileAssetIo::new(&settings.asset_folder, settings.watch_for_changes);
#[cfg(target_arch = "wasm32")]
let source = WasmAssetIo::new(&settings.asset_folder);
#[cfg(target_os = "android")]

View file

@ -1,10 +1,15 @@
use bevy::prelude::*;
use bevy::{asset::AssetServerSettings, prelude::*};
/// Hot reloading allows you to modify assets on disk and they will be "live reloaded" while your
/// game is running. This lets you immediately see the results of your changes without restarting
/// the game. This example illustrates hot reloading mesh changes.
fn main() {
App::new()
// Tell the asset server to watch for asset changes on disk:
.insert_resource(AssetServerSettings {
watch_for_changes: true,
..Default::default()
})
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.run();
@ -14,9 +19,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// Load our mesh:
let scene_handle = asset_server.load("models/monkey/Monkey.gltf#Scene0");
// Tell the asset server to watch for asset changes on disk:
asset_server.watch_for_changes().unwrap();
// Any changes to the mesh will be reloaded automatically! Try making a change to Monkey.gltf.
// You should see the changes immediately show up in your app.