diff --git a/editor/src/asset/mod.rs b/editor/src/asset/mod.rs index 2ccd60df3..768d62f84 100644 --- a/editor/src/asset/mod.rs +++ b/editor/src/asset/mod.rs @@ -685,6 +685,11 @@ impl AssetBrowser { .path .clone(); + if asset_path.as_os_str().is_empty() { + err!("Selecting AssetItem with empty path: {selected_asset}"); + return; + } + if let Some(selection) = entry.selection.as_ref::() { if selection.contains(&asset_path) { return; @@ -830,7 +835,7 @@ impl AssetBrowser { } drop(registry); - for path in paths { + for path in paths.into_iter().filter(|p| !p.as_os_str().is_empty()) { self.add_asset(&path, ui, &engine.resource_manager, &sender); } } diff --git a/editor/src/asset/selection.rs b/editor/src/asset/selection.rs index 0986c4814..c76f6937a 100644 --- a/editor/src/asset/selection.rs +++ b/editor/src/asset/selection.rs @@ -129,7 +129,10 @@ impl AssetSelection { } pub fn selected_path(&self) -> Option<&Path> { - self.resources.first().map(|r| r.path.as_path()) + self.resources + .first() + .map(|r| r.path.as_path()) + .filter(|p| !p.as_os_str().is_empty()) } pub fn selected_import_options(&self) -> Option>> { diff --git a/fyrox-impl/src/engine/executor.rs b/fyrox-impl/src/engine/executor.rs index e4ba49c2d..0e188b098 100644 --- a/fyrox-impl/src/engine/executor.rs +++ b/fyrox-impl/src/engine/executor.rs @@ -376,6 +376,9 @@ fn run_normal( } Event::WindowEvent { event, .. } => { match event { + WindowEvent::Focused(true) => { + engine.resource_manager.state().process_filesystem_events(); + } WindowEvent::CloseRequested => active_event_loop.exit(), WindowEvent::Resized(size) => { if let Err(e) = engine.set_frame_size(size.into()) { diff --git a/fyrox-impl/src/renderer/bundle.rs b/fyrox-impl/src/renderer/bundle.rs index b071bd84c..18787f2ef 100644 --- a/fyrox-impl/src/renderer/bundle.rs +++ b/fyrox-impl/src/renderer/bundle.rs @@ -567,10 +567,10 @@ impl RenderDataBundle { { err_once!( self.data.key() as usize, - "There's no render pass {} in {} shader! \ + "There's no render pass {} in {:?} shader! \ If it is not needed, add it to disabled passes.", render_context.render_pass_name, - shader_state.kind() + shader_data.definition.name, ); } } diff --git a/fyrox-impl/src/resource/model/mod.rs b/fyrox-impl/src/resource/model/mod.rs index ccf561c54..1d8c1e79b 100644 --- a/fyrox-impl/src/resource/model/mod.rs +++ b/fyrox-impl/src/resource/model/mod.rs @@ -760,7 +760,7 @@ impl Display for ModelLoadError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { ModelLoadError::Visit(v) => { - write!(f, "An error occurred while reading a data source {v:?}") + write!(f, "An error occurred while reading a data source: {v}") } ModelLoadError::NotSupported(v) => { write!(f, "Model format is not supported: {v}") diff --git a/fyrox-impl/src/scene/sound/mod.rs b/fyrox-impl/src/scene/sound/mod.rs index 1368a0481..86674f8df 100644 --- a/fyrox-impl/src/scene/sound/mod.rs +++ b/fyrox-impl/src/scene/sound/mod.rs @@ -459,15 +459,13 @@ impl NodeTrait for Sound { ResourceState::Unloaded => { Err("Sound buffer is unloaded because it was never requested.".to_string()) } - ResourceState::LoadError { ref error, .. } => { - match &error.0 { - None => Err("Sound buffer is failed to load, the reason is unknown!" - .to_string()), - Some(err) => { - Err(format!("Sound buffer is failed to load. Reason: {err:?}")) - } + ResourceState::LoadError { ref error, .. } => match &error.0 { + None => { + Err("Sound buffer is failed to load, the reason is unknown!" + .to_string()) } - } + Some(err) => Err(format!("Sound buffer is failed to load. Reason: {err}")), + }, } } None => Err("Sound buffer is not set, the sound won't play!".to_string()), diff --git a/fyrox-material/src/lib.rs b/fyrox-material/src/lib.rs index c6ee1bfa4..2603e6419 100644 --- a/fyrox-material/src/lib.rs +++ b/fyrox-material/src/lib.rs @@ -9,7 +9,6 @@ use fxhash::FxHashMap; use fyrox_core::{ algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4}, color::Color, - futures::executor::block_on, io::FileError, parking_lot::Mutex, reflect::prelude::*, @@ -32,7 +31,7 @@ use std::{ any::Any, error::Error, fmt::{Display, Formatter}, - path::{Path, PathBuf}, + path::Path, sync::Arc, }; use strum_macros::{AsRefStr, EnumString, VariantNames}; @@ -1143,21 +1142,21 @@ impl MaterialResourceExtension for MaterialResource { } fn deep_copy(&self) -> MaterialResource { - if let Err(error) = block_on(self.clone()) { - return MaterialResource::new_load_error( - ResourceKind::Embedded, - PathBuf::default(), - error, - ); - } let material_state = self.header(); match material_state.state { - ResourceState::Pending { .. } - | ResourceState::Unloaded - | ResourceState::LoadError { .. } => { - unreachable!("The resource should be loaded by now") + ResourceState::Unloaded => self.resource_uuid().into(), + ResourceState::Pending { .. } => { + MaterialResource::new_pending(self.resource_uuid(), ResourceKind::External) } - ResourceState::Ok { ref data, .. } => MaterialResource::new_ok( + ResourceState::LoadError { + ref error, + ref path, + } => MaterialResource::new_load_error( + ResourceKind::External, + path.clone(), + error.clone(), + ), + ResourceState::Ok { ref data } => MaterialResource::new_ok( Uuid::new_v4(), ResourceKind::Embedded, (&**data as &dyn Any) diff --git a/fyrox-resource/src/manager.rs b/fyrox-resource/src/manager.rs index fe6c0e2dd..3fd98c30a 100644 --- a/fyrox-resource/src/manager.rs +++ b/fyrox-resource/src/manager.rs @@ -47,6 +47,7 @@ use crate::{ untyped::ResourceKind, Resource, TypedResourceData, UntypedResource, }; +use fxhash::FxHashSet; use fyrox_core::{ futures::executor::block_on, make_relative_path, notify::Event, ok_or_return, some_or_continue, some_or_return, @@ -495,7 +496,6 @@ impl ResourceManager { } /// Find the resource for the given UUID without loading the resource. - /// A new unloaded resource is created if one does not already exist. /// If the resource is not already loading, then it will be returned in /// the [`ResourceState::Unloaded`] state, and [`Self::request_resource`] may /// be used to begin the loading process. @@ -967,20 +967,19 @@ impl ResourceManagerState { /// This may involve updating the registry to reflect changes to the resources, and it may /// involve creating new meta files for resources that are missing meta files. pub fn process_filesystem_events(&mut self) { - while let Some(evt) = self.try_get_event() { + let mut modified_files = FxHashSet::default(); + while let Some(mut evt) = self.try_get_event() { if evt.need_rescan() { info!("Filesystem watcher has forced a rescan!"); self.update_or_load_registry(); + self.reload_resources(); } else { - use notify::event::{CreateKind, DataChange, ModifyKind, RemoveKind, RenameMode}; + use notify::event::{CreateKind, ModifyKind, RemoveKind, RenameMode}; use notify::EventKind; match evt.kind { EventKind::Create(CreateKind::Any | CreateKind::File) => { self.on_create_event(evt.paths.first()) } - EventKind::Modify(ModifyKind::Data(DataChange::Content)) => { - self.on_file_content_event(evt.paths.first()) - } EventKind::Modify(ModifyKind::Name(RenameMode::From)) => { self.on_remove_event(evt.paths.first()) } @@ -991,6 +990,10 @@ impl ResourceManagerState { self.on_remove_event(evt.paths.first()); self.on_create_event(evt.paths.get(1)); } + EventKind::Modify(ModifyKind::Any | ModifyKind::Data(_)) => { + let path = evt.paths.get_mut(0).map(std::mem::take); + modified_files.insert(path); + } EventKind::Remove(RemoveKind::Any | RemoveKind::File) => { self.on_remove_event(evt.paths.first()) } @@ -998,6 +1001,9 @@ impl ResourceManagerState { } } } + for path in modified_files { + self.on_file_content_event(path.as_ref()) + } } fn on_create_event(&mut self, path: Option<&PathBuf>) { @@ -1043,7 +1049,13 @@ impl ResourceManagerState { .safe_lock() .is_supported_resource(&relative_path) { - Self::on_new_resource_file(registry.modify(), relative_path); + Self::on_new_resource_file(registry.modify(), relative_path.clone()); + drop(registry); + if self.try_reload_resource_from_path(&relative_path) { + info!( + "File {relative_path:?} was created, trying to reload a respective resource...", + ); + } } } /// A new resource file has been discovered through an event. Check if there is a corresponding meta file, @@ -1314,8 +1326,11 @@ impl ResourceManagerState { self.built_in_resources.add(resource) } + /// Find the resource for the given UUID without loading the resource. /// Searches the resource manager to find a resource with the given UUID, including built-in resources. - /// If no resource is found, a new UUID is generated and an unloaded resource is returned. + /// If no resource is found, a new unloaded external resource is returned for the given UUID, + /// because it is presumed that this is a real UUID for some resource that is not currently managed + /// and therefore it should be added to the manager. pub fn find_uuid(&mut self, uuid: Uuid) -> UntypedResource { if let Some(built_in_resource) = self.built_in_resources.find_by_uuid(uuid) { return built_in_resource.resource.clone(); @@ -1483,11 +1498,21 @@ impl ResourceManagerState { )); } Err(error) => { - Log::info(format!( - "Resource {path:?} failed to load. Reason: {error:?}", - )); - - resource.commit_error(path.to_path_buf(), error); + if reload { + if resource.is_ok() { + info!("Resource {path:?} failed to reload, keeping the existing version. Reason: {error}"); + } + else + { + info!("Resource {path:?} failed to reload. Reason: {error}"); + resource.commit_error(path.to_path_buf(), error); + } + } + else + { + info!("Resource {path:?} failed to load. Reason: {error}"); + resource.commit_error(path.to_path_buf(), error); + } } } } else { @@ -1628,7 +1653,9 @@ impl ResourceManagerState { } let mut header = resource.lock(); if !header.state.is_loading() { - header.state.switch_to_pending_state(); + if !header.state.is_ok() { + header.state.switch_to_pending_state(); + } drop(header); self.spawn_loading_task(resource, true) } diff --git a/fyrox-resource/src/registry.rs b/fyrox-resource/src/registry.rs index 2acfe58b4..e5110b54c 100644 --- a/fyrox-resource/src/registry.rs +++ b/fyrox-resource/src/registry.rs @@ -283,7 +283,6 @@ impl ResourceRegistryRefMut<'_> { panic!("Registering empty path."); } use std::collections::btree_map::Entry; - //self.registry.paths.insert(uuid, path) match self.registry.paths.entry(uuid) { Entry::Vacant(entry) => { info!("Registered: {uuid} -> {path:?}");