From a7504925f680527b91e0167dc1f86366eb175b2a Mon Sep 17 00:00:00 2001 From: b-guild <148972828+b-guild@users.noreply.github.com> Date: Sun, 19 Oct 2025 04:52:27 -0700 Subject: [PATCH] Correcting registry loading --- editor/src/asset/item.rs | 6 +- editor/src/asset/menu.rs | 6 +- fyrox-core/src/io.rs | 12 +++ fyrox-core/src/lib.rs | 3 + fyrox-impl/src/scene/mod.rs | 13 +--- fyrox-resource/src/io.rs | 125 +++++++++++++++++++++++++++--- fyrox-resource/src/lib.rs | 10 ++- fyrox-resource/src/manager.rs | 134 +++++++++++++++++++++------------ fyrox-resource/src/registry.rs | 112 +++++++-------------------- fyrox-ui/src/lib.rs | 9 ++- 10 files changed, 262 insertions(+), 168 deletions(-) diff --git a/editor/src/asset/item.rs b/editor/src/asset/item.rs index 43223caab..8abcf3505 100644 --- a/editor/src/asset/item.rs +++ b/editor/src/asset/item.rs @@ -233,8 +233,12 @@ impl AssetItem { fn can_be_dropped_to(&self, dest: &AssetItem) -> bool { if self.path.is_file() && dest.path.is_dir() { + let Some(name) = self.path.file_name() else { + return false; + }; + let dest_path = dest.path.join(name); self.resource_manager.as_ref().is_some_and(|rm| { - block_on(rm.can_resource_be_moved(self.path.as_path(), dest.path.as_path(), true)) + block_on(rm.can_resource_be_moved(self.path.as_path(), dest_path, true)) }) } else { self.path.is_dir() && dest.path.is_dir() diff --git a/editor/src/asset/menu.rs b/editor/src/asset/menu.rs index 810d4c696..0cb2fdf81 100644 --- a/editor/src/asset/menu.rs +++ b/editor/src/asset/menu.rs @@ -461,10 +461,8 @@ impl AssetItemContextMenu { .send(Message::ShowInAssetBrowser(final_copy_path)); } Err(err) => Log::err(format!( - "Failed to create a file for resource at path {}. \ - Reason: {:?}", - final_copy_path.display(), - err + "Failed to create a file for resource at path {final_copy_path:?}. \ + Reason: {err}", )), } } diff --git a/fyrox-core/src/io.rs b/fyrox-core/src/io.rs index 027384c3e..2697055f5 100644 --- a/fyrox-core/src/io.rs +++ b/fyrox-core/src/io.rs @@ -48,6 +48,18 @@ impl From for FileError { } } +impl From<&str> for FileError { + fn from(value: &str) -> Self { + Self::Custom(value.to_string()) + } +} + +impl From for FileError { + fn from(value: String) -> Self { + Self::Custom(value) + } +} + #[cfg(target_os = "android")] pub static ANDROID_APP: once_cell::sync::OnceCell = once_cell::sync::OnceCell::new(); diff --git a/fyrox-core/src/lib.rs b/fyrox-core/src/lib.rs index 7137383fc..bbc288741 100644 --- a/fyrox-core/src/lib.rs +++ b/fyrox-core/src/lib.rs @@ -311,6 +311,9 @@ pub fn hash_combine(lhs: u64, rhs: u64) -> u64 { /// The last component of the path is permitted to not exist, so long as the rest of the path exists. pub fn make_relative_path>(path: P) -> Result { let path = path.as_ref(); + if path.as_os_str() == "." { + return Ok(path.to_path_buf()); + } // Canonicalization requires the full path to exist, so remove the file name before // calling canonicalize. let file_name = path.file_name().ok_or(std::io::Error::new( diff --git a/fyrox-impl/src/scene/mod.rs b/fyrox-impl/src/scene/mod.rs index b2d22331f..ec4b4a949 100644 --- a/fyrox-impl/src/scene/mod.rs +++ b/fyrox-impl/src/scene/mod.rs @@ -51,10 +51,7 @@ pub mod tilemap; pub mod transform; use crate::{ - asset::{ - self, io::ResourceIo, manager::ResourceManager, registry::ResourceRegistryStatus, - untyped::UntypedResource, - }, + asset::{self, io::ResourceIo, manager::ResourceManager, untyped::UntypedResource}, core::{ algebra::Vector2, color::Color, @@ -346,14 +343,8 @@ impl SceneLoader { serialization_context: Arc, resource_manager: ResourceManager, ) -> Result<(Self, Vec), VisitError> { - let registry_status = resource_manager - .state() - .resource_registry - .safe_lock() - .status_flag(); // Wait until the registry is fully loaded. - let registry_status = registry_status.await; - if registry_status == ResourceRegistryStatus::Unknown { + if !resource_manager.registry_is_loaded().await { return Err(VisitError::User(format!( "Unable to load a scene from {} path, because the \ resource registry isn't loaded!", diff --git a/fyrox-resource/src/io.rs b/fyrox-resource/src/io.rs index 4cc7abe80..703b6b1c3 100644 --- a/fyrox-resource/src/io.rs +++ b/fyrox-resource/src/io.rs @@ -22,7 +22,9 @@ //! things such as loading assets within archive files use fyrox_core::io::FileError; +use fyrox_core::{make_relative_path, replace_slashes}; use std::ffi::OsStr; +use std::path::Component; use std::{ fmt::Debug, fs::File, @@ -66,6 +68,10 @@ impl FileReader for BufReader { /// Interface wrapping IO operations for doing this like loading files /// for resources pub trait ResourceIo: Send + Sync + 'static { + /// True if writing to files is possible through this object. + fn can_write(&self) -> bool; + /// True if reading the content of directories is possible through this object. + fn can_read_directories(&self) -> bool; /// Attempts to load the file at the provided path returning /// the entire byte contents of the file or an error fn load_file<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, Result, FileError>>; @@ -101,14 +107,13 @@ pub trait ResourceIo: Send + Sync + 'static { dest: &'a Path, ) -> ResourceIoFuture<'a, Result<(), FileError>>; - /// Tries to convert the path to its canonical form (normalize it in other terms). This method - /// should guarantee correct behaviour for relative paths. Symlinks aren't mandatory to + /// Tries to convert the path to its canonical form (normalize it in other terms), + /// and put the path into a form that is suited for use in methods of this object. + /// Each file should have exactly one canonical path. + /// This method should guarantee correct behaviour for relative paths. Symlinks aren't mandatory to /// follow. - fn canonicalize_path<'a>( - &'a self, - path: &'a Path, - ) -> ResourceIoFuture<'a, Result> { - Box::pin(ready(Ok(path.to_owned()))) + fn canonicalize_path<'a>(&'a self, path: &'a Path) -> Result { + Ok(path.to_owned()) } /// Provides an iterator over the paths present in the provided @@ -184,7 +189,50 @@ pub type PathIter = Box>; #[cfg(not(target_arch = "wasm32"))] pub type PathIter = Box + Send>; +/// Remove . and .. directories from a resource path, without accessing the file system, +/// and replace \ with /. There is no requirement that any part of the path actually exists. +/// The path "." is returned if the resulting path would otherwise be empty. +/// +/// Because the file system is not accessed, all paths must be relative to the project root, +/// and this function will return an error if the path tries to go outside of it, such as by .. directories +/// or by being an absolute path. +pub fn normalize_path(path: impl AsRef) -> Result { + let components = path.as_ref().components(); + let mut ret = PathBuf::new(); + + for component in components { + match component { + Component::Prefix(..) | Component::RootDir => { + return Err(format!("Invalid path: {:?}", path.as_ref()).into()); + } + Component::CurDir => {} + Component::ParentDir => { + if !ret.pop() { + panic!("Path may not start with .."); + } + } + Component::Normal(c) => { + ret.push(c); + } + } + } + + if ret.as_os_str().is_empty() { + return Ok(".".into()); + } + + // The resource registry uses normalized paths with `/` slashes, and this step is needed + // mostly on Windows which uses `\` slashes. + Ok(replace_slashes(ret)) +} + impl ResourceIo for FsResourceIo { + fn can_write(&self) -> bool { + cfg!(all(not(target_os = "android"), not(target_arch = "wasm32"))) + } + fn can_read_directories(&self) -> bool { + cfg!(all(not(target_os = "android"), not(target_arch = "wasm32"))) + } fn load_file<'a>(&'a self, path: &'a Path) -> ResourceIoFuture<'a, Result, FileError>> { Box::pin(fyrox_core::io::load_file(path)) } @@ -241,11 +289,12 @@ impl ResourceIo for FsResourceIo { }) } - fn canonicalize_path<'a>( - &'a self, - path: &'a Path, - ) -> ResourceIoFuture<'a, Result> { - Box::pin(async move { Ok(std::fs::canonicalize(path)?) }) + fn canonicalize_path<'a>(&'a self, path: &'a Path) -> Result { + if path.is_absolute() && self.can_read_directories() { + Ok(make_relative_path(path)?) + } else { + normalize_path(path) + } } /// wasm should fallback to the default no-op impl as im not sure if they @@ -348,3 +397,55 @@ impl ResourceIo for FsResourceIo { Box::pin(fyrox_core::io::is_dir(path)) } } + +#[cfg(test)] +mod test { + use super::*; + #[cfg(target_os = "windows")] + #[test] + fn test_normalize_backslash() { + let path = PathBuf::from("alpha\\beta\\..\\gamma"); + assert_eq!(normalize_path(&path).unwrap().as_os_str(), "alpha/gamma"); + } + #[cfg(target_os = "windows")] + #[test] + fn test_canonicalize_backslash() { + let rio = FsResourceIo; + let path = PathBuf::from("src\\test.txt"); + assert_eq!( + rio.canonicalize_path(&path).unwrap().as_os_str(), + "src/test.txt" + ); + } + #[test] + fn test_normalize() { + let path = PathBuf::from("alpha/beta"); + assert_eq!(normalize_path(&path).unwrap().as_os_str(), "alpha/beta"); + let path = PathBuf::from("alpha/.."); + assert_eq!(normalize_path(&path).unwrap().as_os_str(), "."); + } + #[test] + fn test_canonicalize() { + let rio = FsResourceIo; + let path = PathBuf::from("src/test.txt"); + assert_eq!( + rio.canonicalize_path(&path).unwrap().as_os_str(), + "src/test.txt" + ); + let path = PathBuf::from("test.txt"); + assert_eq!( + rio.canonicalize_path(&path).unwrap().as_os_str(), + "test.txt" + ); + let path = PathBuf::from("."); + assert_eq!(rio.canonicalize_path(&path).unwrap().as_os_str(), "."); + let path = PathBuf::from("src") + .canonicalize() + .unwrap() + .join("test.txt"); + assert_eq!( + rio.canonicalize_path(&path).unwrap().as_os_str(), + "src/test.txt" + ); + } +} diff --git a/fyrox-resource/src/lib.rs b/fyrox-resource/src/lib.rs index eb7b153fe..fc13b8705 100644 --- a/fyrox-resource/src/lib.rs +++ b/fyrox-resource/src/lib.rs @@ -927,8 +927,14 @@ mod tests { let res2 = resource_manager.request::(path2); assert_eq!(block_on(res1.clone()).unwrap().data_ref().data, 0); assert_eq!(block_on(res2.clone()).unwrap().data_ref().data, 1); - let new_res1_path = ResourceRegistry::normalize_path(make_file_path(TEST_FOLDER3, 3)); - let new_res2_path = ResourceRegistry::normalize_path(make_file_path(TEST_FOLDER3, 4)); + let new_res1_path = resource_manager + .resource_io() + .canonicalize_path(&make_file_path(TEST_FOLDER3, 3)) + .unwrap(); + let new_res2_path = resource_manager + .resource_io() + .canonicalize_path(&make_file_path(TEST_FOLDER3, 4)) + .unwrap(); block_on(resource_manager.move_resource(res1.as_ref(), &new_res1_path, true)).unwrap(); block_on(resource_manager.move_resource(res2.as_ref(), &new_res2_path, true)).unwrap(); assert_eq!( diff --git a/fyrox-resource/src/manager.rs b/fyrox-resource/src/manager.rs index 93d340023..4b5589630 100644 --- a/fyrox-resource/src/manager.rs +++ b/fyrox-resource/src/manager.rs @@ -163,6 +163,7 @@ impl Display for ResourceRegistrationError { } /// All the required and validated data that is needed to move a resource from the path A to the path B. +#[derive(Debug)] pub struct ResourceMoveContext { relative_src_path: PathBuf, relative_dest_path: PathBuf, @@ -393,6 +394,19 @@ impl ResourceManager { self.state.try_lock_for(timeout) } + /// The resource manager keeps a registry of available resources, and this registry must be loaded + /// before any resources may be requested. This async method returns once the registry loading is complete + /// and it returns true if the loading was successful. It returns false if loading failed. + pub async fn registry_is_loaded(&self) -> bool { + let flag = self + .state() + .resource_registry + .safe_lock() + .status_flag() + .clone(); + flag.await == ResourceRegistryStatus::Loaded + } + /// Returns the ResourceIo used by this resource manager pub fn resource_io(&self) -> Arc { let state = self.state(); @@ -931,32 +945,41 @@ impl ResourceManagerState { // Try to update the registry first. #[cfg(not(any(target_arch = "wasm32", target_os = "android")))] - fyrox_core::futures::executor::block_on(async move { - let new_data = - ResourceRegistry::scan(resource_io.clone(), task_loaders, &path, excluded_folders) - .await; - let mut registry_lock = resource_registry.safe_lock(); - registry_lock.modify().set_container(new_data); - registry_status.mark_as_loaded(); - }); + if resource_io.can_read_directories() && resource_io.can_write() { + fyrox_core::futures::executor::block_on(async move { + let new_data = ResourceRegistry::scan( + resource_io.clone(), + task_loaders, + &path, + excluded_folders, + ) + .await; + let mut registry_lock = resource_registry.safe_lock(); + registry_lock.modify().set_container(new_data); + registry_status.mark_as_loaded(); + }); + } #[cfg(any(target_arch = "wasm32", target_os = "android"))] - self.task_pool.spawn_task(async move { - use crate::registry::RegistryContainerExt; - // Then load the registry. - info!("Trying to load or update the registry at {path:?}..."); - match crate::registry::RegistryContainer::load_from_file(&path, &*resource_io).await { - Ok(registry) => { - let mut registry_lock = resource_registry.safe_lock(); - registry_lock.modify().set_container(registry); - info!("Resource registry was loaded from {path:?} successfully!"); - } - Err(error) => { - err!("Unable to load resource registry! Reason: {error}."); - } - }; - registry_status.mark_as_loaded(); - }); + if !resource_io.can_read_directories() || !resource_io.can_write() { + self.task_pool.spawn_task(async move { + use crate::registry::RegistryContainerExt; + // Then load the registry. + info!("Trying to load or update the registry at {path:?}..."); + match crate::registry::RegistryContainer::load_from_file(&path, &*resource_io).await + { + Ok(registry) => { + let mut registry_lock = resource_registry.safe_lock(); + registry_lock.modify().set_container(registry); + info!("Resource registry was loaded from {path:?} successfully!"); + } + Err(error) => { + err!("Unable to load resource registry! Reason: {error}."); + } + }; + registry_status.mark_as_loaded(); + }); + } } /// Tries to find all the native resources registered in the resource registry, returns a collection @@ -1402,15 +1425,21 @@ impl ResourceManagerState { /// Searches the resource manager and the registry to find a resource with the given path, /// including built-in resources. If no resource is found, a new UUID is generated and the /// path is added to the registry and an unloaded resource is returned. + /// + /// # Panics + /// + /// Panics if the path is invalid, such as if it includes a directory that does not exist + /// or contains invalid characters. pub fn find

(&mut self, path: P) -> UntypedResource where P: AsRef, { - if let Some(built_in_resource) = self.built_in_resources.get(path.as_ref()) { + let path = path.as_ref(); + if let Some(built_in_resource) = self.built_in_resources.get(path) { return built_in_resource.resource.clone(); } - let path = ResourceRegistry::normalize_path(path); + let path = self.resource_io.canonicalize_path(path).unwrap(); if let Some(existing) = self.find_by_resource_path(&path) { existing.clone() @@ -1431,15 +1460,21 @@ impl ResourceManagerState { } /// Tries to load the resource at the given path. + /// + /// # Panics + /// + /// Panics if the path is invalid, such as if it includes a directory that does not exist + /// or contains invalid characters. pub fn request

(&mut self, path: P) -> UntypedResource where P: AsRef, { - if let Some(built_in_resource) = self.built_in_resources.get(path.as_ref()) { + let path = path.as_ref(); + if let Some(built_in_resource) = self.built_in_resources.get(path) { return built_in_resource.resource.clone(); } - let path = ResourceRegistry::normalize_path(path); + let path = self.resource_io.canonicalize_path(path).unwrap(); self.find_or_load(path) } @@ -1500,6 +1535,7 @@ impl ResourceManagerState { self.task_pool.spawn_task(async move { // Wait until the registry is fully loaded. let registry_status = registry_status.await; + if registry_status == ResourceRegistryStatus::Unknown { resource.commit_error( PathBuf::default(), @@ -1518,7 +1554,6 @@ impl ResourceManagerState { in the registry!", resource.resource_uuid(), ); - resource.commit_error(PathBuf::default(), error); return; }; @@ -1676,6 +1711,11 @@ impl ResourceManagerState { /// to the file, otherwise the resource's path should already have been discovered by /// [`ResourceManagerState::update_or_load_registry`]. /// If the manager already has a resource with this resource's UUID, return [`ResourceRegistrationError::AlreadyRegistered`]. + /// + /// # Panics + /// + /// Panics if the path is invalid, such as if it includes a directory that does not exist + /// or contains invalid characters. pub fn register( &mut self, resource: UntypedResource, @@ -1685,7 +1725,7 @@ impl ResourceManagerState { if self.find_by_uuid(resource_uuid).is_some() { return Err(ResourceRegistrationError::AlreadyRegistered); } - let path = ResourceRegistry::normalize_path(path); + let path = self.resource_io.canonicalize_path(path.as_ref()).unwrap(); { let mut header = resource.lock(); header.kind.make_external(); @@ -1774,8 +1814,8 @@ impl ResourceManagerState { let src_path = src_path.as_ref(); let dest_path = dest_path.as_ref(); - let relative_src_path = fyrox_core::make_relative_path(src_path)?; - let relative_dest_path = fyrox_core::make_relative_path(dest_path)?; + let relative_src_path = self.resource_io.canonicalize_path(src_path)?; + let relative_dest_path = self.resource_io.canonicalize_path(dest_path)?; if let Some(file_stem) = relative_dest_path.file_stem() { if !self.resource_io.is_valid_file_name(file_stem) { @@ -1794,8 +1834,8 @@ impl ResourceManagerState { } let registry_lock_guard = self.resource_registry.safe_lock(); - let absolute_registry_dir = if let Some(directory) = registry_lock_guard.directory() { - fyrox_core::replace_slashes(self.resource_io.canonicalize_path(directory).await?) + let registry_dir = if let Some(directory) = registry_lock_guard.directory() { + self.resource_io.canonicalize_path(directory)? } else { return Err(ResourceMovementError::ResourceRegistryLocationUnknown { resource_path: relative_src_path.clone(), @@ -1807,23 +1847,17 @@ impl ResourceManagerState { resource_path: relative_src_path.clone(), })?; - let relative_dest_dir = relative_dest_path.parent().unwrap_or(Path::new(".")); - let absolute_dest_dir = fyrox_core::replace_slashes( - self.resource_io - .canonicalize_path(relative_dest_dir) - .await?, - ); - - let absolute_src_path = fyrox_core::replace_slashes( - self.resource_io - .canonicalize_path(&relative_src_path) - .await?, - ); - if !absolute_dest_dir.starts_with(&absolute_registry_dir) { + let Some(relative_dest_dir) = relative_dest_path.parent() else { + return Err(ResourceMovementError::DestinationPathIsInvalid { + src_path: relative_src_path.clone(), + dest_path: relative_dest_path.clone(), + }); + }; + if !relative_dest_dir.starts_with(®istry_dir) { return Err(ResourceMovementError::OutsideOfRegistry { - absolute_src_path, - absolute_dest_dir, - absolute_registry_dir, + absolute_src_path: relative_src_path, + absolute_dest_dir: relative_dest_dir.to_path_buf(), + absolute_registry_dir: registry_dir, }); } diff --git a/fyrox-resource/src/registry.rs b/fyrox-resource/src/registry.rs index e5110b54c..bf56fc6e2 100644 --- a/fyrox-resource/src/registry.rs +++ b/fyrox-resource/src/registry.rs @@ -23,8 +23,7 @@ use crate::{ core::{ - append_extension, err, info, io::FileError, ok_or_return, parking_lot::Mutex, - replace_slashes, warn, Uuid, + append_extension, err, info, io::FileError, ok_or_return, parking_lot::Mutex, warn, Uuid, }, io::ResourceIo, loader::ResourceLoadersContainer, @@ -37,7 +36,7 @@ use ron::ser::PrettyConfig; use std::{ collections::BTreeMap, future::Future, - path::{Component, Path, PathBuf}, + path::{Path, PathBuf}, pin::Pin, sync::Arc, task::{Context, Poll}, @@ -144,6 +143,7 @@ impl ResourceRegistryStatusFlag { /// Marks the registry as loaded. pub fn mark_as_loaded(&self) { self.mark_as(ResourceRegistryStatus::Loaded); + info!("Resource registry finished loading."); } /// Marks the registry as unknown, due to an error. @@ -175,47 +175,6 @@ impl Future for ResourceRegistryStatusFlag { } } -async fn make_relative_path_async>( - path: P, - io: &dyn ResourceIo, -) -> Result { - let path = path.as_ref(); - // Canonicalization requires the full path to exist, so remove the file name before - // calling canonicalize. - let file_name = path.file_name().ok_or(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("Invalid path: {}", path.display()), - ))?; - let dir = path.parent(); - let dir = if let Some(dir) = dir { - if dir.as_os_str().is_empty() { - Path::new(".") - } else { - dir - } - } else { - Path::new(".") - }; - let canon_path = io - .canonicalize_path(dir) - .await - .map_err(|err| { - FileError::Custom(format!( - "Unable to canonicalize '{}'. Reason: {err:?}", - dir.display() - )) - })? - .join(file_name); - let current_dir = io.canonicalize_path(&std::env::current_dir()?).await?; - match canon_path.strip_prefix(current_dir) { - Ok(relative_path) => Ok(replace_slashes(relative_path)), - Err(err) => Err(FileError::Custom(format!( - "unable to strip prefix from '{}'! Reason: {err}", - canon_path.display() - ))), - } -} - /// A mutable reference to a resource registry. Automatically saves the registry back to a source /// from which it was loaded when an instance of this object is dropped. To prevent saving use /// [`std::mem::forget`] after you've finished working with the mutable reference. @@ -402,36 +361,15 @@ impl ResourceRegistry { self.status.clone() } - /// Normalizes the path by resolving all `.` and `..` and removing any prefixes. Also replaces - /// `\\` slashes to cross-platform `/` slashes. - pub fn normalize_path(path: impl AsRef) -> PathBuf { - let mut components = path.as_ref().components().peekable(); - let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { - components.next(); - PathBuf::from(c.as_os_str()) - } else { - PathBuf::new() - }; - - for component in components { - match component { - Component::Prefix(..) => unreachable!(), - Component::RootDir => { - ret.push(component.as_os_str()); - } - Component::CurDir => {} - Component::ParentDir => { - ret.pop(); - } - Component::Normal(c) => { - ret.push(c); - } - } - } - - // The resource registry uses normalized paths with `/` slashes, and this step is needed - // mostly on Windows which uses `\` slashes. - replace_slashes(ret) + /// Normalizes the path by resolving all `.` and `..` and removing any prefixes. + /// Absolute paths are converted to relative paths by removing the project root prefix, if possible. + /// Also replaces `\\` slashes to cross-platform `/` slashes. + /// + /// # Panics + /// + /// Panics if the given path is invalid, such as if it includes a directory that does not exist. + pub fn normalize_path(&self, path: impl AsRef) -> PathBuf { + self.io.canonicalize_path(path.as_ref()).unwrap() } /// Returns a reference to the actual container of the resource entries. @@ -456,16 +394,18 @@ impl ResourceRegistry { /// Asynchronously saves the registry. pub async fn save(&self) { - match self.paths.save(&self.path, &*self.io).await { - Err(error) => { - err!( - "Unable to write the resource registry at the {:?} path! Reason: {:?}", - self.path, - error - ) - } - Ok(_) => { - info!("The registry was successfully saved to {:?}!", self.path) + if self.io.can_write() { + match self.paths.save(&self.path, &*self.io).await { + Err(error) => { + err!( + "Unable to write the resource registry at the {:?} path! Reason: {:?}", + self.path, + error + ) + } + Ok(_) => { + info!("The registry was successfully saved to {:?}!", self.path) + } } } } @@ -473,7 +413,7 @@ impl ResourceRegistry { /// Same as [`Self::save`], but synchronous. pub fn save_sync(&self) { #[cfg(not(target_arch = "wasm32"))] - { + if self.io.can_write() { match self.paths.save_sync(&self.path, &*self.io) { Err(error) => { err!( @@ -554,7 +494,7 @@ impl ResourceRegistry { .collect::>(); while let Some(fs_path) = paths_to_visit.pop() { - let path = match make_relative_path_async(&fs_path, &*resource_io).await { + let path = match resource_io.canonicalize_path(&fs_path) { Ok(path) => path, Err(err) => { warn!( diff --git a/fyrox-ui/src/lib.rs b/fyrox-ui/src/lib.rs index 885503abb..483b433af 100644 --- a/fyrox-ui/src/lib.rs +++ b/fyrox-ui/src/lib.rs @@ -322,8 +322,10 @@ use crate::{ use copypasta::ClipboardContext; use fxhash::{FxHashMap, FxHashSet}; use fyrox_resource::{ - io::FsResourceIo, io::ResourceIo, manager::ResourceManager, untyped::UntypedResource, Resource, - ResourceData, + io::{FsResourceIo, ResourceIo}, + manager::ResourceManager, + untyped::UntypedResource, + Resource, ResourceData, }; use serde::{Deserialize, Serialize}; use std::{ @@ -3270,6 +3272,9 @@ impl UserInterface { resource_manager: ResourceManager, io: &dyn ResourceIo, ) -> Result { + if !resource_manager.registry_is_loaded().await { + return Err("The resource registry is unavailable!".to_string().into()); + } let mut ui = { let mut visitor = Visitor::load_from_memory(&io.load_file(path.as_ref()).await?)?; let (sender, receiver) = mpsc::channel();