diff --git a/Cargo.toml b/Cargo.toml index a7f4c0c..63ae3e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,10 +7,10 @@ keywords = ["gamedev", "networking", "wasm", "bevy"] license = "MIT OR Apache-2.0" name = "bevy_web_asset" repository = "https://github.com/johanhelsing/bevy_web_asset" -version = "0.5.0" +version = "0.6.0" [dependencies] -bevy = {version = "0.9", default-features = false, features = ["bevy_asset"]} +bevy = {version = "0.10", default-features = false, features = ["bevy_asset"]} # Copied from https://github.com/bevyengine/bevy/blob/main/crates/bevy_asset/Cargo.toml crossbeam-channel = "0.5.0" @@ -26,9 +26,10 @@ wasm-bindgen-futures = "0.4" web-sys = {version = "0.3.22", default-features = false} [dev-dependencies] -bevy = {version = "0.9", default-features = false, features = [ +bevy = {version = "0.10", default-features = false, features = [ "bevy_asset", + "bevy_core_pipeline", + "bevy_sprite", "png", - "render", "x11", # GitHub Actions runners don't have libxkbcommon installed, so can't use Wayland ]} diff --git a/examples/web_image.rs b/examples/web_image.rs index 2703e55..98f895a 100644 --- a/examples/web_image.rs +++ b/examples/web_image.rs @@ -4,11 +4,9 @@ use bevy_web_asset::WebAssetPlugin; fn main() { App::new() // The web asset plugin must be inserted before the `AssetPlugin` so - // that the asset plugin doesn't create another instance of an asset - // server. WebAssetPlugin will handle initialization of AssetPlugin - // so we remove it from the default plugins group. + // that the AssetServer is already created by the time the AssetPlugin is initialized. .add_plugin(WebAssetPlugin::default()) - .add_plugins(DefaultPlugins.build().disable::()) + .add_plugins(DefaultPlugins) .add_startup_system(setup) .run(); } diff --git a/src/filesystem_watcher.rs b/src/filesystem_watcher.rs deleted file mode 100644 index 6579ec1..0000000 --- a/src/filesystem_watcher.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crossbeam_channel::Receiver; -use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Result, Watcher}; -use std::path::Path; - -/// See the [original implementation](https://github.com/bevyengine/bevy/blob/main/crates/bevy_asset/src/filesystem_watcher.rs) -pub struct FilesystemWatcher { - pub watcher: RecommendedWatcher, - pub receiver: Receiver>, -} - -impl Default for FilesystemWatcher { - fn default() -> Self { - let (sender, receiver) = crossbeam_channel::unbounded(); - let watcher: RecommendedWatcher = RecommendedWatcher::new( - move |res| { - sender.send(res).expect("Watch event send failure."); - }, - Config::default(), - ) - .expect("Failed to create filesystem watcher."); - FilesystemWatcher { watcher, receiver } - } -} - -impl FilesystemWatcher { - /// Watch for changes recursively at the provided path. - pub fn watch>(&mut self, path: P) -> Result<()> { - self.watcher.watch(path.as_ref(), RecursiveMode::Recursive) - } -} - -use bevy::prelude::*; -use bevy::utils::HashSet; -use crossbeam_channel::TryRecvError; - -use super::WebAssetIo; - -pub fn filesystem_watcher_system(asset_server: Res) { - let mut changed = HashSet::default(); - - let asset_io = if let Some(asset_io) = asset_server.asset_io().downcast_ref::() { - asset_io - } else { - return; - }; - - if let Ok(filesystem_watcher) = asset_io.filesystem_watcher.read() { - if let Some(ref watcher) = *filesystem_watcher { - 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, - .. - } = event - { - for path in &paths { - if !changed.contains(path) { - let relative_path = path.strip_prefix(&asset_io.root_path).unwrap(); - asset_server.reload_asset(relative_path); - } - } - changed.extend(paths); - } - } - } - } -} diff --git a/src/lib.rs b/src/lib.rs index c80b458..ac0308d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,5 @@ mod web_asset_io; mod web_asset_plugin; -mod filesystem_watcher; - pub use web_asset_io::WebAssetIo; pub use web_asset_plugin::WebAssetPlugin; diff --git a/src/web_asset_io.rs b/src/web_asset_io.rs index 1b87f93..880d661 100644 --- a/src/web_asset_io.rs +++ b/src/web_asset_io.rs @@ -1,16 +1,12 @@ -use bevy::asset::{AssetIo, AssetIoError, BoxedFuture}; -use std::{ - path::{Path, PathBuf}, - sync::{Arc, RwLock}, +use bevy::{ + asset::{AssetIo, AssetIoError}, + utils::BoxedFuture, }; - -use super::filesystem_watcher::FilesystemWatcher; +use std::path::{Path, PathBuf}; /// Wraps the default bevy AssetIo and adds support for loading http urls pub struct WebAssetIo { - pub(crate) root_path: PathBuf, pub(crate) default_io: Box, - pub(crate) filesystem_watcher: Arc>>, } fn is_http(path: &Path) -> bool { @@ -33,7 +29,7 @@ impl AssetIo for WebAssetIo { .map_err(|e| e.dyn_into::().unwrap()); if let Err(err) = &response { - warn!("Failed to fetch asset {uri}: {err:?}"); + // warn!("Failed to fetch asset {uri}: {err:?}"); } let response = response.map_err(|_| AssetIoError::NotFound(path.to_path_buf()))?; @@ -55,7 +51,6 @@ impl AssetIo for WebAssetIo { .body_bytes() .await .map_err(|_| AssetIoError::NotFound(path.to_path_buf()))?; - Ok(bytes) }); @@ -72,8 +67,12 @@ impl AssetIo for WebAssetIo { self.default_io.read_directory(path) } - fn watch_path_for_changes(&self, path: &Path) -> Result<(), AssetIoError> { - if is_http(path) { + fn watch_path_for_changes( + &self, + to_watch: &Path, + to_reload: Option, + ) -> Result<(), AssetIoError> { + if is_http(to_watch) { // TODO: we could potentially start polling over http here // but should probably only be done if the server supports caching @@ -81,25 +80,12 @@ impl AssetIo for WebAssetIo { Ok(()) // Pretend everything is fine } else { - // We can now simply use our own watcher - - let absolute_path = self.root_path.join(path); - - if let Ok(mut filesystem_watcher) = self.filesystem_watcher.write() { - if let Some(ref mut watcher) = *filesystem_watcher { - watcher - .watch(&absolute_path) - .map_err(|_error| AssetIoError::PathWatchError(absolute_path))?; - } - } - - Ok(()) + self.default_io.watch_path_for_changes(to_watch, to_reload) } } fn watch_for_changes(&self) -> Result<(), AssetIoError> { - // self.filesystem_watcher is created in `web_asset_plugin.rs` - Ok(()) // This could create self.network_watcher + self.default_io.watch_for_changes() } fn is_dir(&self, path: &Path) -> bool { diff --git a/src/web_asset_plugin.rs b/src/web_asset_plugin.rs index 284ccd9..57c7f10 100644 --- a/src/web_asset_plugin.rs +++ b/src/web_asset_plugin.rs @@ -1,14 +1,10 @@ -use bevy::asset::FileAssetIo; use bevy::prelude::*; -use std::sync::{Arc, RwLock}; -use super::filesystem_watcher::FilesystemWatcher; use super::WebAssetIo; /// Add this plugin to bevy to support loading http and https urls. /// /// Needs to be added before Bevy's `DefaultPlugins`. -/// Also, make sure `AssetPlugin` is not loaded through `DefaultPlugins`. /// /// # Example /// @@ -17,61 +13,19 @@ use super::WebAssetIo; /// # use bevy_web_asset::WebAssetPlugin; /// /// let mut app = App::new(); -/// // The web asset plugin should be added instead of the `AssetPlugin` -/// // Internally, WebAssetPlugin will create an AssetPlugin and hook into -/// // it in the right places -/// app.add_plugin(WebAssetPlugin::default()); -/// app.add_plugins(DefaultPlugins.build().disable::()); +/// app.add_plugin(WebAssetPlugin); +/// app.add_plugins(DefaultPlugins); /// ``` ///}); #[derive(Default)] -pub struct WebAssetPlugin { - /// Settings for the underlying (regular) AssetPlugin - pub asset_plugin: AssetPlugin, -} +pub struct WebAssetPlugin; impl Plugin for WebAssetPlugin { fn build(&self, app: &mut App) { - // First, configure the underlying plugin - // We use out own watcher, so `watch_for_changes` is always false - let asset_plugin = AssetPlugin { - asset_folder: self.asset_plugin.asset_folder.clone(), - watch_for_changes: false, - }; - - // Create the `FileAssetIo` wrapper - let asset_io = { - // This makes calling `WebAssetIo::watch_for_changes` redundant - let filesystem_watcher = match self.asset_plugin.watch_for_changes { - true => Arc::new(RwLock::new(Some(FilesystemWatcher::default()))), - false => Arc::new(RwLock::new(None)), - }; - - // Create the `FileAssetIo` - let default_io = asset_plugin.create_platform_default_asset_io(); - - // The method doesn't change, so we just use `FileAssetIo`'s - let root_path = FileAssetIo::get_base_path().join(&self.asset_plugin.asset_folder); - - WebAssetIo { - default_io, - root_path, - filesystem_watcher, - } + let asset_io = WebAssetIo { + default_io: AssetPlugin::default().create_platform_default_asset_io(), }; - // Add the asset server with our `WebAssetIo` wrapping `FileAssetIo` app.insert_resource(AssetServer::new(asset_io)); - - // Add the asset plugin - app.add_plugin(asset_plugin); - - // Optionally add the filesystem watcher system - if self.asset_plugin.watch_for_changes { - app.add_system_to_stage( - bevy::asset::AssetStage::LoadAssets, - super::filesystem_watcher::filesystem_watcher_system, - ); - } } }