From 8fa4562a8118bc190a1056a057e73684bb6d5710 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Fri, 21 Aug 2020 07:12:22 -0400 Subject: [PATCH 1/5] Remove AssetLoadRequestHandler, rewrite bevy_assets internals, tune api --- crates/bevy_asset/Cargo.toml | 3 +- crates/bevy_asset/src/asset_server.rs | 405 ++++++++---------- crates/bevy_asset/src/assets.rs | 33 +- crates/bevy_asset/src/handle.rs | 60 ++- crates/bevy_asset/src/lib.rs | 2 - crates/bevy_asset/src/load_request.rs | 70 --- crates/bevy_asset/src/loader.rs | 69 ++- crates/bevy_audio/src/audio_source.rs | 4 +- crates/bevy_audio/src/lib.rs | 2 +- crates/bevy_gltf/src/lib.rs | 3 +- crates/bevy_gltf/src/loader.rs | 4 +- crates/bevy_render/src/lib.rs | 4 +- .../src/texture/hdr_texture_loader.rs | 4 +- .../src/texture/image_texture_loader.rs | 4 +- crates/bevy_scene/src/lib.rs | 2 +- crates/bevy_scene/src/loaded_scenes.rs | 4 +- crates/bevy_text/src/font_loader.rs | 4 +- crates/bevy_text/src/lib.rs | 2 +- examples/2d/texture_atlas.rs | 15 +- examples/asset/asset_loading.rs | 8 +- 20 files changed, 348 insertions(+), 354 deletions(-) delete mode 100644 crates/bevy_asset/src/load_request.rs diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index 235a53413d224..05ee978fa2065 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -27,4 +27,5 @@ crossbeam-channel = "0.4.2" anyhow = "1.0" thiserror = "1.0" log = { version = "0.4", features = ["release_max_level_info"] } -notify = { version = "5.0.0-pre.2", optional = true } \ No newline at end of file +notify = { version = "5.0.0-pre.2", optional = true } +rayon = "1.3" \ No newline at end of file diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 01aea3b9666f8..8d4f8ae7eaaa3 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -1,16 +1,17 @@ use crate::{ - filesystem_watcher::FilesystemWatcher, AssetLoadError, AssetLoadRequestHandler, AssetLoader, - Assets, Handle, HandleId, LoadRequest, + filesystem_watcher::FilesystemWatcher, AssetLoadError, AssetLoader, Assets, ChannelAssetLoader, + Handle, HandleId, HandleUntyped, LoadData, UntypedLoader, }; use anyhow::Result; -use bevy_ecs::{Res, Resource, Resources}; +use bevy_ecs::{Res, Resource}; use crossbeam_channel::TryRecvError; +use rayon::{ThreadPool, ThreadPoolBuilder}; use std::{ + any::TypeId, collections::{HashMap, HashSet}, env, fs, io, path::{Path, PathBuf}, sync::{Arc, RwLock}, - thread, }; use thiserror::Error; @@ -34,20 +35,16 @@ pub enum AssetServerError { Io(#[from] io::Error), #[error("Failed to watch asset folder.")] AssetWatchError { path: PathBuf }, -} - -struct LoaderThread { - // NOTE: these must remain private. the LoaderThread Arc counters are used to determine thread liveness - // if there is one reference, the loader thread is dead. if there are two references, the loader thread is active - requests: Arc>>, + #[error("cannot load asset as specified type")] + IncorrectType, } /// Info about a specific asset, such as its path and its current load state #[derive(Clone, Debug)] -pub struct AssetInfo { - pub handle_id: HandleId, - pub path: PathBuf, - pub load_state: LoadState, +struct AssetInfo { + handle_id: HandleId, + path: PathBuf, + load_state: LoadState, } /// The load state of an asset @@ -70,16 +67,13 @@ impl LoadState { /// Loads assets from the filesystem on background threads pub struct AssetServer { + threadpool: ThreadPool, asset_folders: RwLock>, - loader_threads: RwLock>, - max_loader_threads: usize, - asset_handlers: Arc>>>, - // TODO: this is a hack to enable retrieving generic AssetLoaders. there must be a better way! - loaders: Vec, - extension_to_handler_index: HashMap, + loaders: Vec<(TypeId, Arc)>, extension_to_loader_index: HashMap, asset_info: RwLock>, asset_info_paths: RwLock>, + #[cfg(feature = "filesystem_watcher")] filesystem_watcher: Arc>>, } @@ -89,12 +83,13 @@ impl Default for AssetServer { AssetServer { #[cfg(feature = "filesystem_watcher")] filesystem_watcher: Arc::new(RwLock::new(None)), - max_loader_threads: 4, + + threadpool: ThreadPoolBuilder::new() + .num_threads(4) + .build() + .expect("unable to create asset server threadpool"), asset_folders: Default::default(), - loader_threads: Default::default(), - asset_handlers: Default::default(), loaders: Default::default(), - extension_to_handler_index: Default::default(), extension_to_loader_index: Default::default(), asset_info_paths: Default::default(), asset_info: Default::default(), @@ -103,47 +98,75 @@ impl Default for AssetServer { } impl AssetServer { - pub fn add_handler(&mut self, asset_handler: T) - where - T: AssetLoadRequestHandler, - { - let mut asset_handlers = self.asset_handlers.write().unwrap(); - let handler_index = asset_handlers.len(); - for extension in asset_handler.extensions().iter() { - self.extension_to_handler_index - .insert(extension.to_string(), handler_index); - } + /// Only loads items that are loaded into an asset of type `T`. + /// All other items are ignored. + pub fn load_folder>( + &self, + path: P, + ) -> Result>, AssetServerError> { + let path = path.as_ref(); + // Could be more efficient + let root_path = self.get_root_path()?; + let asset_folder = root_path.join(path); + let handles = self + .load_assets_in_folder_recursive(&asset_folder, Some(TypeId::of::()))? + .into_iter() + .map(|h| h.id.into()) + .collect(); + self.asset_folders.write().unwrap().push(asset_folder); + Ok(handles) + } + + pub fn load_folder_all>( + &self, + path: P, + ) -> Result, AssetServerError> { + let root_path = self.get_root_path()?; + let asset_folder = root_path.join(path); + let handles = self.load_assets_in_folder_recursive(&asset_folder, None)?; + self.asset_folders.write().unwrap().push(asset_folder); + Ok(handles) + } - asset_handlers.push(Box::new(asset_handler)); + pub fn load>(&self, path: P) -> Result, AssetServerError> { + let path = path.as_ref(); + Ok(self + .load_any_internal(path, Some(TypeId::of::()))? + .id + .into()) } - pub fn add_loader(&mut self, loader: TLoader) + pub fn load_sync>( + &self, + assets: &mut Assets, + path: P, + ) -> Result, AssetServerError> where - TLoader: AssetLoader, - TAsset: 'static, + T: 'static, { - let loader_index = self.loaders.len(); - for extension in loader.extensions().iter() { + let path = path.as_ref(); + if let Some(&index) = path.extension().and_then(|ext| { self.extension_to_loader_index - .insert(extension.to_string(), loader_index); + .get(ext.to_str().expect("extension should be a valid string")) + }) { + let untyped_loader = Arc::clone(&self.loaders[index].1); + // Check that the types match. + let loader: &dyn AssetLoader = untyped_loader + .downcast_loader::() + .expect("tried to request an asset loader of the wrong type"); + + let asset = loader.load_from_file(path)?; + Ok(assets.add(asset)) + } else { + Err(AssetServerError::MissingAssetHandler) } - - let mut resources = Resources::default(); - resources.insert::>>(Box::new(loader)); - self.loaders.push(resources); } - pub fn load_asset_folder>( - &self, - path: P, - ) -> Result, AssetServerError> { - let root_path = self.get_root_path()?; - let asset_folder = root_path.join(path); - let handle_ids = self.load_assets_in_folder_recursive(&asset_folder)?; - self.asset_folders.write().unwrap().push(asset_folder); - Ok(handle_ids) + pub fn load_any>(&self, path: P) -> Result { + self.load_any_internal(path, None) } + /// TODO: Check handle type? pub fn get_handle>(&self, path: P) -> Option> { self.asset_info_paths .read() @@ -209,7 +232,7 @@ impl AssetServer { if !changed.contains(path) { let root_path = asset_server.get_root_path().unwrap(); let relative_path = path.strip_prefix(root_path).unwrap(); - match asset_server.load_untyped(relative_path) { + match asset_server.load_any(relative_path) { Ok(_) => {} Err(AssetServerError::AssetLoadError(error)) => panic!("{:?}", error), Err(_) => {} @@ -235,101 +258,7 @@ impl AssetServer { } } - // TODO: add type checking here. people shouldn't be able to request a Handle for a Mesh asset - pub fn load>(&self, path: P) -> Result, AssetServerError> { - self.load_untyped(path).map(Handle::from) - } - - pub fn load_sync>( - &self, - assets: &mut Assets, - path: P, - ) -> Result, AssetServerError> - where - T: 'static, - { - let path = path.as_ref(); - if let Some(ref extension) = path.extension() { - if let Some(index) = self.extension_to_loader_index.get( - extension - .to_str() - .expect("extension should be a valid string"), - ) { - let handle_id = HandleId::new(); - let resources = &self.loaders[*index]; - let loader = resources.get::>>().unwrap(); - let asset = loader.load_from_file(path)?; - let handle = Handle::from(handle_id); - assets.set(handle, asset); - Ok(handle) - } else { - Err(AssetServerError::MissingAssetHandler) - } - } else { - Err(AssetServerError::MissingAssetHandler) - } - } - - pub fn load_untyped>(&self, path: P) -> Result { - let path = path.as_ref(); - if let Some(ref extension) = path.extension() { - if let Some(index) = self.extension_to_handler_index.get( - extension - .to_str() - .expect("Extension should be a valid string."), - ) { - let mut new_version = 0; - let handle_id = { - let mut asset_info = self.asset_info.write().unwrap(); - let mut asset_info_paths = self.asset_info_paths.write().unwrap(); - if let Some(asset_info) = asset_info_paths - .get(path) - .and_then(|handle_id| asset_info.get_mut(&handle_id)) - { - asset_info.load_state = - if let LoadState::Loaded(_version) = asset_info.load_state { - new_version += 1; - LoadState::Loading(new_version) - } else { - LoadState::Loading(new_version) - }; - asset_info.handle_id - } else { - let handle_id = HandleId::new(); - asset_info.insert( - handle_id, - AssetInfo { - handle_id, - path: path.to_owned(), - load_state: LoadState::Loading(new_version), - }, - ); - asset_info_paths.insert(path.to_owned(), handle_id); - handle_id - } - }; - - self.send_request_to_loader_thread(LoadRequest { - handle_id, - path: path.to_owned(), - handler_index: *index, - version: new_version, - }); - - // TODO: watching each asset explicitly is a simpler implementation, its possible it would be more efficient to watch - // folders instead (when possible) - #[cfg(feature = "filesystem_watcher")] - Self::watch_path_for_changes(&mut self.filesystem_watcher.write().unwrap(), path)?; - Ok(handle_id) - } else { - Err(AssetServerError::MissingAssetHandler) - } - } else { - Err(AssetServerError::MissingAssetHandler) - } - } - - pub fn set_load_state(&self, handle_id: HandleId, load_state: LoadState) { + pub(crate) fn set_load_state(&self, handle_id: HandleId, load_state: LoadState) { if let Some(asset_info) = self.asset_info.write().unwrap().get_mut(&handle_id) { if load_state.get_version() >= asset_info.load_state.get_version() { asset_info.load_state = load_state; @@ -337,22 +266,25 @@ impl AssetServer { } } - pub fn get_load_state_untyped(&self, handle_id: HandleId) -> Option { + pub fn get_load_state(&self, handle: H) -> Option + where + H: Into, + { self.asset_info .read() .unwrap() - .get(&handle_id) + .get(&handle.into()) .map(|asset_info| asset_info.load_state.clone()) } - pub fn get_load_state(&self, handle: Handle) -> Option { - self.get_load_state_untyped(handle.id) - } - - pub fn get_group_load_state(&self, handle_ids: &[HandleId]) -> Option { + pub fn get_group_load_state(&self, handles: I) -> Option + where + I: IntoIterator, + I::Item: Into, + { let mut load_state = LoadState::Loaded(0); - for handle_id in handle_ids.iter() { - match self.get_load_state_untyped(*handle_id) { + for handle in handles.into_iter() { + match self.get_load_state(handle) { Some(LoadState::Loaded(_)) => continue, Some(LoadState::Loading(_)) => { load_state = LoadState::Loading(0); @@ -365,60 +297,11 @@ impl AssetServer { Some(load_state) } - fn send_request_to_loader_thread(&self, load_request: LoadRequest) { - // NOTE: This lock makes the call to Arc::strong_count safe. Removing (or reordering) it could result in undefined behavior - let mut loader_threads = self.loader_threads.write().unwrap(); - if loader_threads.len() < self.max_loader_threads { - let loader_thread = LoaderThread { - requests: Arc::new(RwLock::new(vec![load_request])), - }; - let requests = loader_thread.requests.clone(); - loader_threads.push(loader_thread); - Self::start_thread(self.asset_handlers.clone(), requests); - } else { - let most_free_thread = loader_threads - .iter() - .min_by_key(|l| l.requests.read().unwrap().len()) - .unwrap(); - let mut requests = most_free_thread.requests.write().unwrap(); - requests.push(load_request); - // if most free thread only has one reference, the thread as spun down. if so, we need to spin it back up! - if Arc::strong_count(&most_free_thread.requests) == 1 { - Self::start_thread( - self.asset_handlers.clone(), - most_free_thread.requests.clone(), - ); - } - } - } - - fn start_thread( - request_handlers: Arc>>>, - requests: Arc>>, - ) { - thread::spawn(move || { - loop { - let request = { - let mut current_requests = requests.write().unwrap(); - if current_requests.len() == 0 { - // if there are no requests, spin down the thread - break; - } - - current_requests.pop().unwrap() - }; - - let handlers = request_handlers.read().unwrap(); - let request_handler = &handlers[request.handler_index]; - request_handler.handle_request(&request); - } - }); - } - fn load_assets_in_folder_recursive( &self, path: &Path, - ) -> Result, AssetServerError> { + only_ty: Option, + ) -> Result, AssetServerError> { if !path.is_dir() { return Err(AssetServerError::AssetFolderNotADirectory( path.to_str().unwrap().to_string(), @@ -426,28 +309,110 @@ impl AssetServer { } let root_path = self.get_root_path()?; - let mut handle_ids = Vec::new(); + let mut handles = Vec::new(); for entry in fs::read_dir(path)? { let entry = entry?; let child_path = entry.path(); if child_path.is_dir() { - handle_ids.extend(self.load_assets_in_folder_recursive(&child_path)?); + handles.extend(self.load_assets_in_folder_recursive(&child_path, only_ty)?); } else { let relative_child_path = child_path.strip_prefix(&root_path).unwrap(); - let handle = match self.load_untyped( - relative_child_path - .to_str() - .expect("Path should be a valid string"), - ) { + let handle = match self.load_any_internal(relative_child_path, only_ty) { Ok(handle) => handle, - Err(AssetServerError::MissingAssetHandler) => continue, + Err(AssetServerError::IncorrectType) + | Err(AssetServerError::MissingAssetHandler) => continue, Err(err) => return Err(err), }; - handle_ids.push(handle); + handles.push(handle); } } - Ok(handle_ids) + Ok(handles) + } + + fn load_any_internal>( + &self, + path: P, + expected_ty: Option, + ) -> Result { + let path = path.as_ref(); + let index = if let Some(&index) = path.extension().and_then(|ext| { + self.extension_to_loader_index + .get(ext.to_str().expect("extension should be a valid string")) + }) { + index + } else { + return Err(AssetServerError::MissingAssetHandler); + }; + + let (type_id, untyped_loader) = &self.loaders[index]; + + if let Some(expected_ty) = expected_ty { + if *type_id != expected_ty { + return Err(AssetServerError::IncorrectType); + } + } + + let untyped_loader = Arc::clone(untyped_loader); + + let mut version = 0; + let handle_id = { + let mut asset_info = self.asset_info.write().unwrap(); + let mut asset_info_paths = self.asset_info_paths.write().unwrap(); + if let Some(asset_info) = asset_info_paths + .get(path) + .and_then(|handle_id| asset_info.get_mut(&handle_id)) + { + asset_info.load_state = if let LoadState::Loaded(_version) = asset_info.load_state { + version += 1; + LoadState::Loading(version) + } else { + LoadState::Loading(version) + }; + asset_info.handle_id + } else { + let handle_id = HandleId::new(); + asset_info.insert( + handle_id, + AssetInfo { + handle_id, + path: path.to_owned(), + load_state: LoadState::Loading(version), + }, + ); + asset_info_paths.insert(path.to_owned(), handle_id); + handle_id + } + }; + + let load_data = LoadData { + path: path.to_owned(), + handle_id, + version, + }; + + self.threadpool + .spawn_fifo(move || untyped_loader.load_from_file(load_data)); + + // TODO: watching each asset explicitly is a simpler implementation, its possible it would be more efficient to watch + // folders instead (when possible) + #[cfg(feature = "filesystem_watcher")] + Self::watch_path_for_changes(&mut self.filesystem_watcher.write().unwrap(), path)?; + + Ok(HandleUntyped { + id: handle_id, + type_id: *type_id, + }) + } + + pub(crate) fn add_cal(&mut self, cal: ChannelAssetLoader) { + let loader_index = self.loaders.len(); + for extension in cal.loader.extensions().iter() { + self.extension_to_loader_index + .insert(extension.to_string(), loader_index); + } + + self.loaders.push((TypeId::of::(), Arc::new(cal))); } } diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 201614f862503..54addbf3683df 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -1,5 +1,5 @@ use crate::{ - update_asset_storage_system, AssetChannel, AssetLoader, AssetServer, ChannelAssetHandler, + update_asset_storage_system, AssetChannel, AssetLoader, AssetServer, ChannelAssetLoader, Handle, HandleId, }; use bevy_app::{prelude::Events, AppBuilder}; @@ -115,10 +115,9 @@ pub trait AddAsset { fn add_asset(&mut self) -> &mut Self where T: Send + Sync + 'static; - fn add_asset_loader(&mut self) -> &mut Self + fn add_asset_loader(&mut self) -> &mut Self where - TLoader: AssetLoader + FromResources, - TAsset: Send + Sync + 'static; + Loader: AssetLoader + FromResources; } impl AddAsset for AppBuilder { @@ -135,33 +134,33 @@ impl AddAsset for AppBuilder { .add_event::>() } - fn add_asset_loader(&mut self) -> &mut Self + fn add_asset_loader(&mut self) -> &mut Self where - TLoader: AssetLoader + FromResources, - TAsset: Send + Sync + 'static, + Loader: AssetLoader + FromResources, { { - if !self.resources().contains::>() { - self.resources_mut().insert(AssetChannel::::new()); + if !self.resources().contains::>() { + self.resources_mut() + .insert(AssetChannel::::new()); self.add_system_to_stage( crate::stage::LOAD_ASSETS, - update_asset_storage_system::.system(), + update_asset_storage_system::.system(), ); } + let asset_channel = self .resources() - .get::>() + .get::>() .expect("AssetChannel should always exist at this point."); let mut asset_server = self .resources() .get_mut::() .expect("AssetServer does not exist. Consider adding it as a resource."); - asset_server.add_loader(TLoader::from_resources(self.resources())); - let handler = ChannelAssetHandler::new( - TLoader::from_resources(self.resources()), - asset_channel.sender.clone(), - ); - asset_server.add_handler(handler); + + asset_server.add_cal(ChannelAssetLoader { + sender: asset_channel.sender.clone(), + loader: Box::new(Loader::from_resources(self.resources())), + }); } self } diff --git a/crates/bevy_asset/src/handle.rs b/crates/bevy_asset/src/handle.rs index c51bc60f159e0..dfe7db581d1ac 100644 --- a/crates/bevy_asset/src/handle.rs +++ b/crates/bevy_asset/src/handle.rs @@ -5,7 +5,7 @@ use std::{ use bevy_property::{Properties, Property}; use serde::{Deserialize, Serialize}; -use std::{any::TypeId, marker::PhantomData}; +use std::{any::TypeId, convert::TryFrom, marker::PhantomData}; use uuid::Uuid; /// The ID of the "default" asset @@ -103,18 +103,48 @@ impl From<[u8; 16]> for Handle { } } -impl From for Handle -where - T: 'static, -{ - fn from(handle: HandleUntyped) -> Self { +impl Into for Handle { + fn into(self) -> HandleId { + self.id + } +} + +impl Into for &'_ Handle { + fn into(self) -> HandleId { + self.id + } +} + +// impl From for Handle +// where +// T: 'static, +// { +// fn from(handle: HandleUntyped) -> Self { +// if TypeId::of::() == handle.type_id { +// Handle { +// id: handle.id, +// marker: PhantomData::default(), +// } +// } else { +// panic!("attempted to convert untyped handle to incorrect typed handle") +// } +// } +// } + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct HandleUpcastError(()); + +impl TryFrom for Handle { + type Error = HandleUpcastError; + + fn try_from(handle: HandleUntyped) -> Result { if TypeId::of::() == handle.type_id { - Handle { + Ok(Handle { id: handle.id, marker: PhantomData::default(), - } + }) } else { - panic!("attempted to convert untyped handle to incorrect typed handle") + Err(HandleUpcastError(())) } } } @@ -189,3 +219,15 @@ where } } } + +impl Into for HandleUntyped { + fn into(self) -> HandleId { + self.id + } +} + +impl Into for &'_ HandleUntyped { + fn into(self) -> HandleId { + self.id + } +} diff --git a/crates/bevy_asset/src/lib.rs b/crates/bevy_asset/src/lib.rs index b2751a37fee1e..a59bf944e83c4 100644 --- a/crates/bevy_asset/src/lib.rs +++ b/crates/bevy_asset/src/lib.rs @@ -3,13 +3,11 @@ mod assets; #[cfg(feature = "filesystem_watcher")] mod filesystem_watcher; mod handle; -mod load_request; mod loader; pub use asset_server::*; pub use assets::*; pub use handle::*; -pub use load_request::*; pub use loader::*; /// The names of asset stages in an App Schedule diff --git a/crates/bevy_asset/src/load_request.rs b/crates/bevy_asset/src/load_request.rs deleted file mode 100644 index 3da04fd952275..0000000000000 --- a/crates/bevy_asset/src/load_request.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::{AssetLoadError, AssetLoader, AssetResult, AssetVersion, Handle, HandleId}; -use anyhow::Result; -use crossbeam_channel::Sender; -use fs::File; -use io::Read; -use std::{fs, io, path::PathBuf}; - -/// A request from an [AssetServer](crate::AssetServer) to load an asset. -#[derive(Debug)] -pub struct LoadRequest { - pub path: PathBuf, - pub handle_id: HandleId, - pub handler_index: usize, - pub version: AssetVersion, -} - -/// Handles load requests from an AssetServer -pub trait AssetLoadRequestHandler: Send + Sync + 'static { - fn handle_request(&self, load_request: &LoadRequest); - fn extensions(&self) -> &[&str]; -} - -pub(crate) struct ChannelAssetHandler -where - TLoader: AssetLoader, - TAsset: 'static, -{ - sender: Sender>, - loader: TLoader, -} - -impl ChannelAssetHandler -where - TLoader: AssetLoader, -{ - pub fn new(loader: TLoader, sender: Sender>) -> Self { - ChannelAssetHandler { sender, loader } - } - - fn load_asset(&self, load_request: &LoadRequest) -> Result { - let mut file = File::open(&load_request.path)?; - let mut bytes = Vec::new(); - file.read_to_end(&mut bytes)?; - let asset = self.loader.from_bytes(&load_request.path, bytes)?; - Ok(asset) - } -} - -impl AssetLoadRequestHandler for ChannelAssetHandler -where - TLoader: AssetLoader + 'static, - TAsset: Send + 'static, -{ - fn handle_request(&self, load_request: &LoadRequest) { - let result = self.load_asset(load_request); - let asset_result = AssetResult { - handle: Handle::from(load_request.handle_id), - result, - path: load_request.path.clone(), - version: load_request.version, - }; - self.sender - .send(asset_result) - .expect("loaded asset should have been sent"); - } - - fn extensions(&self) -> &[&str] { - self.loader.extensions() - } -} diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index db398a17d3677..a196469e689e7 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -1,11 +1,12 @@ -use crate::{AssetServer, AssetVersion, Assets, Handle, LoadState}; +use crate::{AssetServer, AssetVersion, Assets, Handle, HandleId, LoadState}; use anyhow::Result; use bevy_ecs::{Res, ResMut, Resource}; use crossbeam_channel::{Receiver, Sender, TryRecvError}; use fs::File; -use io::Read; use std::{ - fs, io, + any::Any, + fs, + io::{self, Read}, path::{Path, PathBuf}, }; use thiserror::Error; @@ -19,11 +20,13 @@ pub enum AssetLoadError { LoaderError(#[from] anyhow::Error), } -/// A loader for a given asset of type `T` -pub trait AssetLoader: Send + Sync + 'static { - fn from_bytes(&self, asset_path: &Path, bytes: Vec) -> Result; +/// A loader for a given asset type. +pub trait AssetLoader: Send + Sync + 'static { + type Asset: Send + Sync + 'static; + fn extensions(&self) -> &[&str]; - fn load_from_file(&self, asset_path: &Path) -> Result { + fn from_bytes(&self, asset_path: &Path, bytes: Vec) -> Result; + fn load_from_file(&self, asset_path: &Path) -> Result { let mut file = File::open(asset_path)?; let mut bytes = Vec::new(); file.read_to_end(&mut bytes)?; @@ -32,8 +35,54 @@ pub trait AssetLoader: Send + Sync + 'static { } } +pub(crate) struct ChannelAssetLoader { + pub(crate) sender: Sender>, + pub(crate) loader: Box>, +} + +pub(crate) trait UntypedLoader: Send + Sync + Any { + fn load_from_file(&self, data: LoadData); + fn cast_to_any(&self) -> &dyn Any; +} + +impl dyn UntypedLoader { + pub fn downcast_loader(&self) -> Option<&dyn AssetLoader> { + self.cast_to_any() + .downcast_ref::>() + .map(|cal| &*cal.loader) + } +} + +impl UntypedLoader for ChannelAssetLoader +where + A: Send + Sync + 'static, +{ + fn load_from_file(&self, data: LoadData) { + let result = self.loader.load_from_file(&data.path); + let msg = AssetResult { + result, + handle: Handle::from_id(data.handle_id), + path: data.path, + version: data.version, + }; + self.sender + .send(msg) + .expect("loaded asset should have been sent"); + } + + fn cast_to_any(&self) -> &dyn Any { + self + } +} + +pub(crate) struct LoadData { + pub(crate) path: PathBuf, + pub(crate) handle_id: HandleId, + pub(crate) version: AssetVersion, +} + /// The result of loading an asset of type `T` -pub struct AssetResult { +pub(crate) struct AssetResult { pub result: Result, pub handle: Handle, pub path: PathBuf, @@ -41,7 +90,7 @@ pub struct AssetResult { } /// A channel to send and receive [AssetResult]s -pub struct AssetChannel { +pub(crate) struct AssetChannel { pub sender: Sender>, pub receiver: Receiver>, } @@ -55,7 +104,7 @@ impl AssetChannel { } /// Reads [AssetResult]s from an [AssetChannel] and updates the [Assets] collection and [LoadState] accordingly -pub fn update_asset_storage_system( +pub(crate) fn update_asset_storage_system( asset_channel: Res>, asset_server: Res, mut assets: ResMut>, diff --git a/crates/bevy_audio/src/audio_source.rs b/crates/bevy_audio/src/audio_source.rs index 16a032e3ae31e..b85d80e433aff 100644 --- a/crates/bevy_audio/src/audio_source.rs +++ b/crates/bevy_audio/src/audio_source.rs @@ -18,7 +18,9 @@ impl AsRef<[u8]> for AudioSource { #[derive(Default)] pub struct Mp3Loader; -impl AssetLoader for Mp3Loader { +impl AssetLoader for Mp3Loader { + type Asset = AudioSource; + fn from_bytes(&self, _asset_path: &Path, bytes: Vec) -> Result { Ok(AudioSource { bytes: Arc::new(bytes), diff --git a/crates/bevy_audio/src/lib.rs b/crates/bevy_audio/src/lib.rs index 46270278f58da..26aaf50f6cf7c 100644 --- a/crates/bevy_audio/src/lib.rs +++ b/crates/bevy_audio/src/lib.rs @@ -20,7 +20,7 @@ impl Plugin for AudioPlugin { fn build(&self, app: &mut AppBuilder) { app.init_resource::() .add_asset::() - .add_asset_loader::() + .add_asset_loader::() .add_system_to_stage(stage::POST_UPDATE, play_queued_audio_system.system()); } } diff --git a/crates/bevy_gltf/src/lib.rs b/crates/bevy_gltf/src/lib.rs index 2d5f7db90d3d0..eee0850d2d056 100644 --- a/crates/bevy_gltf/src/lib.rs +++ b/crates/bevy_gltf/src/lib.rs @@ -3,7 +3,6 @@ pub use loader::*; use bevy_app::prelude::*; use bevy_asset::AddAsset; -use bevy_render::mesh::Mesh; /// Adds support for GLTF file loading to Apps #[derive(Default)] @@ -11,6 +10,6 @@ pub struct GltfPlugin; impl Plugin for GltfPlugin { fn build(&self, app: &mut AppBuilder) { - app.add_asset_loader::(); + app.add_asset_loader::(); } } diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index ad8441657e5a3..884bee36a940e 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -15,7 +15,9 @@ use thiserror::Error; #[derive(Default)] pub struct GltfLoader; -impl AssetLoader for GltfLoader { +impl AssetLoader for GltfLoader { + type Asset = Mesh; + fn from_bytes(&self, asset_path: &Path, bytes: Vec) -> Result { let mesh = load_gltf(asset_path, bytes)?; Ok(mesh) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 623e7088c513e..777738330fccb 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -81,11 +81,11 @@ impl Plugin for RenderPlugin { fn build(&self, app: &mut AppBuilder) { #[cfg(feature = "png")] { - app.add_asset_loader::(); + app.add_asset_loader::(); } #[cfg(feature = "hdr")] { - app.add_asset_loader::(); + app.add_asset_loader::(); } app.add_stage_after(bevy_asset::stage::ASSET_EVENTS, stage::RENDER_RESOURCE) diff --git a/crates/bevy_render/src/texture/hdr_texture_loader.rs b/crates/bevy_render/src/texture/hdr_texture_loader.rs index 013c9c3c081e2..f5fe6b5b1020f 100644 --- a/crates/bevy_render/src/texture/hdr_texture_loader.rs +++ b/crates/bevy_render/src/texture/hdr_texture_loader.rs @@ -8,7 +8,9 @@ use std::path::Path; #[derive(Clone, Default)] pub struct HdrTextureLoader; -impl AssetLoader for HdrTextureLoader { +impl AssetLoader for HdrTextureLoader { + type Asset = Texture; + fn from_bytes(&self, _asset_path: &Path, bytes: Vec) -> Result { let format = TextureFormat::Rgba32Float; debug_assert_eq!( diff --git a/crates/bevy_render/src/texture/image_texture_loader.rs b/crates/bevy_render/src/texture/image_texture_loader.rs index 06b1b04be2c40..450074f2a0821 100644 --- a/crates/bevy_render/src/texture/image_texture_loader.rs +++ b/crates/bevy_render/src/texture/image_texture_loader.rs @@ -10,7 +10,9 @@ use std::path::Path; #[derive(Clone, Default)] pub struct ImageTextureLoader; -impl AssetLoader for ImageTextureLoader { +impl AssetLoader for ImageTextureLoader { + type Asset = Texture; + fn from_bytes(&self, asset_path: &Path, bytes: Vec) -> Result { use bevy_core::AsBytes; diff --git a/crates/bevy_scene/src/lib.rs b/crates/bevy_scene/src/lib.rs index a6698398a452b..013416de02173 100644 --- a/crates/bevy_scene/src/lib.rs +++ b/crates/bevy_scene/src/lib.rs @@ -23,7 +23,7 @@ pub const SCENE_STAGE: &str = "scene"; impl Plugin for ScenePlugin { fn build(&self, app: &mut AppBuilder) { app.add_asset::() - .add_asset_loader::() + .add_asset_loader::() .init_resource::() .add_stage_after(stage::EVENT_UPDATE, SCENE_STAGE) .add_system_to_stage(SCENE_STAGE, scene_spawner_system.thread_local_system()); diff --git a/crates/bevy_scene/src/loaded_scenes.rs b/crates/bevy_scene/src/loaded_scenes.rs index 99b61617a1488..14640dc700e37 100644 --- a/crates/bevy_scene/src/loaded_scenes.rs +++ b/crates/bevy_scene/src/loaded_scenes.rs @@ -23,7 +23,9 @@ impl FromResources for SceneLoader { } } -impl AssetLoader for SceneLoader { +impl AssetLoader for SceneLoader { + type Asset = Scene; + fn from_bytes(&self, _asset_path: &Path, bytes: Vec) -> Result { let registry = self.property_type_registry.read().unwrap(); let mut deserializer = bevy_ron::de::Deserializer::from_bytes(&bytes)?; diff --git a/crates/bevy_text/src/font_loader.rs b/crates/bevy_text/src/font_loader.rs index c1e8db7d9f4cf..a62bad6324b0d 100644 --- a/crates/bevy_text/src/font_loader.rs +++ b/crates/bevy_text/src/font_loader.rs @@ -6,7 +6,9 @@ use std::path::Path; #[derive(Default)] pub struct FontLoader; -impl AssetLoader for FontLoader { +impl AssetLoader for FontLoader { + type Asset = Font; + fn from_bytes(&self, _asset_path: &Path, bytes: Vec) -> Result { Ok(Font::try_from_bytes(bytes)?) } diff --git a/crates/bevy_text/src/lib.rs b/crates/bevy_text/src/lib.rs index d74d0164e5855..19dbd5f49ee8c 100644 --- a/crates/bevy_text/src/lib.rs +++ b/crates/bevy_text/src/lib.rs @@ -24,6 +24,6 @@ impl Plugin for TextPlugin { fn build(&self, app: &mut AppBuilder) { app.add_asset::() .add_asset::() - .add_asset_loader::(); + .add_asset_loader::(); } } diff --git a/examples/2d/texture_atlas.rs b/examples/2d/texture_atlas.rs index 7299bd14ea519..54716bf7e5aa9 100644 --- a/examples/2d/texture_atlas.rs +++ b/examples/2d/texture_atlas.rs @@ -1,8 +1,4 @@ -use bevy::{ - asset::{HandleId, LoadState}, - prelude::*, - sprite::TextureAtlasBuilder, -}; +use bevy::{asset::LoadState, prelude::*, sprite::TextureAtlasBuilder}; /// In this example we generate a new texture atlas (sprite sheet) from a folder containing individual sprites fn main() { @@ -16,14 +12,12 @@ fn main() { #[derive(Default)] pub struct RpgSpriteHandles { - handles: Vec, + handles: Vec>, atlas_loaded: bool, } fn setup(mut rpg_sprite_handles: ResMut, asset_server: Res) { - rpg_sprite_handles.handles = asset_server - .load_asset_folder("assets/textures/rpg") - .unwrap(); + rpg_sprite_handles.handles = asset_server.load_folder("assets/textures/rpg").unwrap(); } fn load_atlas( @@ -42,8 +36,7 @@ fn load_atlas( if let Some(LoadState::Loaded(_)) = asset_server.get_group_load_state(&rpg_sprite_handles.handles) { - for texture_id in rpg_sprite_handles.handles.iter() { - let handle = Handle::from_id(*texture_id); + for &handle in rpg_sprite_handles.handles.iter() { let texture = textures.get(&handle).unwrap(); texture_atlas_builder.add_texture(handle, &texture); } diff --git a/examples/asset/asset_loading.rs b/examples/asset/asset_loading.rs index 216f32d3cd82f..a6b5438924cff 100644 --- a/examples/asset/asset_loading.rs +++ b/examples/asset/asset_loading.rs @@ -17,7 +17,13 @@ fn setup( ) { // You can load all assets in a folder like this. They will be loaded in parallel without blocking asset_server - .load_asset_folder("assets/models/monkey") + .load_folder_all("assets/models/monkey") + .unwrap(); + + // If you only want a certain kind of asset from within a folder, + // you can also import like this: + asset_server + .load_folder::("assets/models/monkey") .unwrap(); // Then any asset in the folder can be accessed like this: From 4841750aa93480b1801df92024ae7b7ef5cd38f4 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Fri, 21 Aug 2020 07:17:08 -0400 Subject: [PATCH 2/5] Fix newline ending file --- crates/bevy_asset/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_asset/Cargo.toml b/crates/bevy_asset/Cargo.toml index 05ee978fa2065..5084fe3746ee2 100644 --- a/crates/bevy_asset/Cargo.toml +++ b/crates/bevy_asset/Cargo.toml @@ -28,4 +28,4 @@ anyhow = "1.0" thiserror = "1.0" log = { version = "0.4", features = ["release_max_level_info"] } notify = { version = "5.0.0-pre.2", optional = true } -rayon = "1.3" \ No newline at end of file +rayon = "1.3" From ac1d59bf1557a88a9c74e5cf8dca3c5934864754 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Fri, 21 Aug 2020 07:36:17 -0400 Subject: [PATCH 3/5] Add more comments and visibility changes --- crates/bevy_asset/src/asset_server.rs | 90 ++++++++++++++++----------- crates/bevy_asset/src/assets.rs | 2 +- crates/bevy_asset/src/loader.rs | 6 +- examples/2d/texture_atlas.rs | 6 +- 4 files changed, 62 insertions(+), 42 deletions(-) diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index 8d4f8ae7eaaa3..ec4b351c1c4ed 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -44,23 +44,23 @@ pub enum AssetServerError { struct AssetInfo { handle_id: HandleId, path: PathBuf, - load_state: LoadState, + load_state: LoadStatus, } /// The load state of an asset #[derive(Clone, Debug, Eq, PartialEq)] -pub enum LoadState { +pub enum LoadStatus { Loading(AssetVersion), Loaded(AssetVersion), Failed(AssetVersion), } -impl LoadState { +impl LoadStatus { pub fn get_version(&self) -> AssetVersion { match *self { - LoadState::Loaded(version) => version, - LoadState::Loading(version) => version, - LoadState::Failed(version) => version, + LoadStatus::Loaded(version) => version, + LoadStatus::Loading(version) => version, + LoadStatus::Failed(version) => version, } } } @@ -98,7 +98,10 @@ impl Default for AssetServer { } impl AssetServer { - /// Only loads items that are loaded into an asset of type `T`. + /// Asynchronously load assets of type `T` from the + /// specified folder. + /// # Note: + /// Only loads assets of type `T`. /// All other items are ignored. pub fn load_folder>( &self, @@ -117,6 +120,9 @@ impl AssetServer { Ok(handles) } + /// Asynchronously load all assets in the specified folder. + /// The returned handles can be cast into `Handle` + /// later on. pub fn load_folder_all>( &self, path: P, @@ -128,6 +134,9 @@ impl AssetServer { Ok(handles) } + /// Asynchronously load an asset of type `T` from the specified path. + /// If the the asset cannot be loaded as a `T`, then `AssetServerError::IncorrectType` + /// will be returned. pub fn load>(&self, path: P) -> Result, AssetServerError> { let path = path.as_ref(); Ok(self @@ -136,6 +145,8 @@ impl AssetServer { .into()) } + /// Synch\ronously load an asset of type `T` from the specified path. + /// This will block until the asset has been fully loaded. pub fn load_sync>( &self, assets: &mut Assets, @@ -162,10 +173,15 @@ impl AssetServer { } } + /// Load an asset of any type from the specified path. + /// The returned handle can be cast into `Handle` later + /// on. pub fn load_any>(&self, path: P) -> Result { self.load_any_internal(path, None) } + /// Attempt to get the handle to a loaded asset of type `T`. + /// If the asset has not finished loading, `None` will be returned. /// TODO: Check handle type? pub fn get_handle>(&self, path: P) -> Option> { self.asset_info_paths @@ -175,6 +191,21 @@ impl AssetServer { .map(|handle_id| Handle::from(*handle_id)) } + /// Start watching for changes to already registered files and directories. + #[cfg(feature = "filesystem_watcher")] + pub fn watch_for_changes(&self) -> Result<(), AssetServerError> { + let mut filesystem_watcher = self.filesystem_watcher.write().unwrap(); + + let _ = filesystem_watcher.get_or_insert_with(FilesystemWatcher::default); + // watch current files + let asset_info_paths = self.asset_info_paths.read().unwrap(); + for asset_path in asset_info_paths.keys() { + Self::watch_path_for_changes(&mut filesystem_watcher, asset_path)?; + } + + Ok(()) + } + #[cfg(feature = "filesystem_watcher")] fn watch_path_for_changes>( filesystem_watcher: &mut Option, @@ -192,21 +223,7 @@ impl AssetServer { } #[cfg(feature = "filesystem_watcher")] - pub fn watch_for_changes(&self) -> Result<(), AssetServerError> { - let mut filesystem_watcher = self.filesystem_watcher.write().unwrap(); - - let _ = filesystem_watcher.get_or_insert_with(FilesystemWatcher::default); - // watch current files - let asset_info_paths = self.asset_info_paths.read().unwrap(); - for asset_path in asset_info_paths.keys() { - Self::watch_path_for_changes(&mut filesystem_watcher, asset_path)?; - } - - Ok(()) - } - - #[cfg(feature = "filesystem_watcher")] - pub fn filesystem_watcher_system(asset_server: Res) { + pub(crate) fn filesystem_watcher_system(asset_server: Res) { use notify::event::{Event, EventKind, ModifyKind}; let mut changed = HashSet::new(); @@ -258,7 +275,7 @@ impl AssetServer { } } - pub(crate) fn set_load_state(&self, handle_id: HandleId, load_state: LoadState) { + pub(crate) fn set_load_status(&self, handle_id: HandleId, load_state: LoadStatus) { if let Some(asset_info) = self.asset_info.write().unwrap().get_mut(&handle_id) { if load_state.get_version() >= asset_info.load_state.get_version() { asset_info.load_state = load_state; @@ -266,7 +283,8 @@ impl AssetServer { } } - pub fn get_load_state(&self, handle: H) -> Option + /// Get the current load status of an asset indicated by `handle`. + pub fn get_load_status(&self, handle: H) -> Option where H: Into, { @@ -277,19 +295,20 @@ impl AssetServer { .map(|asset_info| asset_info.load_state.clone()) } - pub fn get_group_load_state(&self, handles: I) -> Option + /// Check the least-common-denominator load status of a group of asset handles. + pub fn get_group_load_status(&self, handles: I) -> Option where I: IntoIterator, I::Item: Into, { - let mut load_state = LoadState::Loaded(0); + let mut load_state = LoadStatus::Loaded(0); for handle in handles.into_iter() { - match self.get_load_state(handle) { - Some(LoadState::Loaded(_)) => continue, - Some(LoadState::Loading(_)) => { - load_state = LoadState::Loading(0); + match self.get_load_status(handle) { + Some(LoadStatus::Loaded(_)) => continue, + Some(LoadStatus::Loading(_)) => { + load_state = LoadStatus::Loading(0); } - Some(LoadState::Failed(_)) => return Some(LoadState::Failed(0)), + Some(LoadStatus::Failed(_)) => return Some(LoadStatus::Failed(0)), None => return None, } } @@ -364,11 +383,12 @@ impl AssetServer { .get(path) .and_then(|handle_id| asset_info.get_mut(&handle_id)) { - asset_info.load_state = if let LoadState::Loaded(_version) = asset_info.load_state { + asset_info.load_state = if let LoadStatus::Loaded(_version) = asset_info.load_state + { version += 1; - LoadState::Loading(version) + LoadStatus::Loading(version) } else { - LoadState::Loading(version) + LoadStatus::Loading(version) }; asset_info.handle_id } else { @@ -378,7 +398,7 @@ impl AssetServer { AssetInfo { handle_id, path: path.to_owned(), - load_state: LoadState::Loading(version), + load_state: LoadStatus::Loading(version), }, ); asset_info_paths.insert(path.to_owned(), handle_id); diff --git a/crates/bevy_asset/src/assets.rs b/crates/bevy_asset/src/assets.rs index 54addbf3683df..b6e31b70822ff 100644 --- a/crates/bevy_asset/src/assets.rs +++ b/crates/bevy_asset/src/assets.rs @@ -102,7 +102,7 @@ impl Assets { self.assets.remove(&handle) } - pub fn asset_event_system( + pub(crate) fn asset_event_system( mut events: ResMut>>, mut assets: ResMut>, ) { diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index a196469e689e7..c2a1293c00ae9 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -1,4 +1,4 @@ -use crate::{AssetServer, AssetVersion, Assets, Handle, HandleId, LoadState}; +use crate::{AssetServer, AssetVersion, Assets, Handle, HandleId, LoadStatus}; use anyhow::Result; use bevy_ecs::{Res, ResMut, Resource}; use crossbeam_channel::{Receiver, Sender, TryRecvError}; @@ -115,11 +115,11 @@ pub(crate) fn update_asset_storage_system( Ok(asset) => { assets.set(result.handle, asset); asset_server - .set_load_state(result.handle.id, LoadState::Loaded(result.version)); + .set_load_status(result.handle.id, LoadStatus::Loaded(result.version)); } Err(err) => { asset_server - .set_load_state(result.handle.id, LoadState::Failed(result.version)); + .set_load_status(result.handle.id, LoadStatus::Failed(result.version)); log::error!("Failed to load asset: {:?}", err); } }, diff --git a/examples/2d/texture_atlas.rs b/examples/2d/texture_atlas.rs index 54716bf7e5aa9..af5f7c1bd51cf 100644 --- a/examples/2d/texture_atlas.rs +++ b/examples/2d/texture_atlas.rs @@ -1,4 +1,4 @@ -use bevy::{asset::LoadState, prelude::*, sprite::TextureAtlasBuilder}; +use bevy::{asset::LoadStatus, prelude::*, sprite::TextureAtlasBuilder}; /// In this example we generate a new texture atlas (sprite sheet) from a folder containing individual sprites fn main() { @@ -33,8 +33,8 @@ fn load_atlas( } let mut texture_atlas_builder = TextureAtlasBuilder::default(); - if let Some(LoadState::Loaded(_)) = - asset_server.get_group_load_state(&rpg_sprite_handles.handles) + if let Some(LoadStatus::Loaded(_)) = + asset_server.get_group_load_status(&rpg_sprite_handles.handles) { for &handle in rpg_sprite_handles.handles.iter() { let texture = textures.get(&handle).unwrap(); From 3ac9b8200aa2faeaffa249be8f828ae87f5a7e09 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Fri, 21 Aug 2020 07:38:55 -0400 Subject: [PATCH 4/5] More comment fixes --- crates/bevy_asset/src/asset_server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_asset/src/asset_server.rs b/crates/bevy_asset/src/asset_server.rs index ec4b351c1c4ed..1bc9ab43b6c08 100644 --- a/crates/bevy_asset/src/asset_server.rs +++ b/crates/bevy_asset/src/asset_server.rs @@ -65,7 +65,7 @@ impl LoadStatus { } } -/// Loads assets from the filesystem on background threads +/// Asynchronously loads assets from the filesystem on background threads! pub struct AssetServer { threadpool: ThreadPool, asset_folders: RwLock>, @@ -145,7 +145,7 @@ impl AssetServer { .into()) } - /// Synch\ronously load an asset of type `T` from the specified path. + /// Synchronously load an asset of type `T` from the specified path. /// This will block until the asset has been fully loaded. pub fn load_sync>( &self, From c6679ebe440a30ab6635cfcdd8c42ff39c4ef753 Mon Sep 17 00:00:00 2001 From: Lachlan Sneff Date: Fri, 21 Aug 2020 07:41:58 -0400 Subject: [PATCH 5/5] Remove handle::from_untyped, instead use Handle::try_from or HandleUntyped::try_into --- crates/bevy_asset/src/handle.rs | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/crates/bevy_asset/src/handle.rs b/crates/bevy_asset/src/handle.rs index dfe7db581d1ac..9980745d0406e 100644 --- a/crates/bevy_asset/src/handle.rs +++ b/crates/bevy_asset/src/handle.rs @@ -72,17 +72,6 @@ impl Handle { marker: PhantomData, } } - - pub fn from_untyped(untyped_handle: HandleUntyped) -> Option> - where - T: 'static, - { - if TypeId::of::() == untyped_handle.type_id { - Some(Handle::from_id(untyped_handle.id)) - } else { - None - } - } } impl From for Handle { @@ -115,22 +104,6 @@ impl Into for &'_ Handle { } } -// impl From for Handle -// where -// T: 'static, -// { -// fn from(handle: HandleUntyped) -> Self { -// if TypeId::of::() == handle.type_id { -// Handle { -// id: handle.id, -// marker: PhantomData::default(), -// } -// } else { -// panic!("attempted to convert untyped handle to incorrect typed handle") -// } -// } -// } - #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct HandleUpcastError(());