From 202ed9a7b347a74d9eb85686dbe420031dd8fcab Mon Sep 17 00:00:00 2001 From: Dmitry Stepanov Date: Sat, 5 Apr 2025 11:17:15 +0300 Subject: [PATCH] ability to create metadata files + fixed all tests --- .gitignore | 2 + fyrox-impl/src/scene/mesh/mod.rs | 2 +- fyrox-impl/src/scene/mesh/surface.rs | 4 +- fyrox-impl/src/scene/mod.rs | 3 +- fyrox-impl/src/scene/node/mod.rs | 19 ++++++--- fyrox-impl/src/scene/particle_system/mod.rs | 2 +- fyrox-impl/src/scene/sprite.rs | 2 +- fyrox-resource/src/lib.rs | 44 ++++++++++++--------- fyrox-resource/src/metadata.rs | 25 ++++++++++-- fyrox-resource/src/registry.rs | 15 ++++++- fyrox-sound/src/renderer/hrtf.rs | 3 +- fyrox-ui/src/style/mod.rs | 6 +-- 12 files changed, 86 insertions(+), 41 deletions(-) diff --git a/.gitignore b/.gitignore index 01c784807..c86acbba3 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ /fyrox-resource/test.txt /fyrox-core-derive/test_output /fyrox-resource/test_output +/fyrox-resource/test_output1 +/fyrox-resource/test_output2 /fyrox-impl/test_output history.bin settings.ron diff --git a/fyrox-impl/src/scene/mesh/mod.rs b/fyrox-impl/src/scene/mesh/mod.rs index 33b19b132..d1582ddb2 100644 --- a/fyrox-impl/src/scene/mesh/mod.rs +++ b/fyrox-impl/src/scene/mesh/mod.rs @@ -304,7 +304,7 @@ impl RenderDataBundleStorageTrait for BatchContainer { /// fn create_cube_mesh(graph: &mut Graph) -> Handle { /// let cube_surface_data = SurfaceData::make_cube(Matrix4::identity()); /// -/// let cube_surface = SurfaceBuilder::new(SurfaceResource::new_ok(ResourceKind::Embedded, cube_surface_data)).build(); +/// let cube_surface = SurfaceBuilder::new(SurfaceResource::new_embedded(cube_surface_data)).build(); /// /// MeshBuilder::new(BaseBuilder::new()) /// .with_surfaces(vec![cube_surface]) diff --git a/fyrox-impl/src/scene/mesh/surface.rs b/fyrox-impl/src/scene/mesh/surface.rs index 7c77d0047..312ae1916 100644 --- a/fyrox-impl/src/scene/mesh/surface.rs +++ b/fyrox-impl/src/scene/mesh/surface.rs @@ -1213,7 +1213,7 @@ impl SurfaceResourceExtension for SurfaceResource { /// /// let data = SurfaceData::new(vertex_buffer, triangle_buffer); /// -/// SurfaceBuilder::new(SurfaceResource::new_ok(ResourceKind::Embedded, data)).build() +/// SurfaceBuilder::new(SurfaceResource::new_embedded(data)).build() /// } /// ``` /// @@ -1230,7 +1230,7 @@ impl SurfaceResourceExtension for SurfaceResource { /// # }; /// use fyrox_resource::untyped::ResourceKind; /// fn create_cone_surface() -> Surface { -/// SurfaceBuilder::new(SurfaceResource::new_ok(ResourceKind::Embedded, SurfaceData::make_cone( +/// SurfaceBuilder::new(SurfaceResource::new_embedded(SurfaceData::make_cone( /// 16, /// 1.0, /// 2.0, diff --git a/fyrox-impl/src/scene/mod.rs b/fyrox-impl/src/scene/mod.rs index cb3e224c7..64433188f 100644 --- a/fyrox-impl/src/scene/mod.rs +++ b/fyrox-impl/src/scene/mod.rs @@ -532,8 +532,7 @@ impl Scene { /// let mut scene = Scene::new(); /// /// MeshBuilder::new(BaseBuilder::new()) - /// .with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_ok( ResourceKind::Embedded, - /// SurfaceData::make_cube(Default::default()), + /// .with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_embedded(SurfaceData::make_cube(Default::default()), /// )) /// .build()]) /// .build(&mut scene.graph); diff --git a/fyrox-impl/src/scene/node/mod.rs b/fyrox-impl/src/scene/node/mod.rs index bb316a703..0628e5d22 100644 --- a/fyrox-impl/src/scene/node/mod.rs +++ b/fyrox-impl/src/scene/node/mod.rs @@ -718,11 +718,7 @@ mod test { // Initialize resource manager and re-load the scene. let resource_manager = ResourceManager::new(Arc::new(Default::default())); - engine::initialize_resource_manager_loaders( - &resource_manager, - Arc::new(SerializationContext::new()), - ); - resource_manager.update_and_load_registry("test_output/resources.registry"); + let serialization_context = SerializationContext::new(); serialization_context .script_constructors @@ -734,6 +730,13 @@ mod test { .iter() .any(|s| s.1.source_path == file!())); + engine::initialize_resource_manager_loaders( + &resource_manager, + Arc::new(serialization_context), + ); + + resource_manager.update_and_load_registry("test_output/resources.registry"); + let root_asset = block_on(resource_manager.request::(root_asset_path)).unwrap(); // Create root resource instance in a derived resource. @@ -760,6 +763,12 @@ mod test { assert!(!mesh.surfaces()[0].material.is_modified()); mesh.set_cast_shadows(false); save_scene(&mut derived, derived_asset_path); + resource_manager + .state() + .resource_registry + .lock() + .write_metadata(Uuid::new_v4(), derived_asset_path.to_path_buf()) + .unwrap(); } // Reload the derived asset and check its content. diff --git a/fyrox-impl/src/scene/particle_system/mod.rs b/fyrox-impl/src/scene/particle_system/mod.rs index 9e346be83..08d4cfef9 100644 --- a/fyrox-impl/src/scene/particle_system/mod.rs +++ b/fyrox-impl/src/scene/particle_system/mod.rs @@ -217,7 +217,7 @@ impl Visit for ParticleSystemRng { /// ) /// .with_radius(0.01) /// .build()]) -/// .with_material(MaterialResource::new_ok(Default::default(), material)) +/// .with_material(MaterialResource::new_embedded(material)) /// .build(graph); /// } /// ``` diff --git a/fyrox-impl/src/scene/sprite.rs b/fyrox-impl/src/scene/sprite.rs index 70dad931e..2a19da233 100644 --- a/fyrox-impl/src/scene/sprite.rs +++ b/fyrox-impl/src/scene/sprite.rs @@ -147,7 +147,7 @@ impl VertexTrait for SpriteVertex { /// .bind("smoke.png", resource_manager.request::("smoke.png")); /// /// SpriteBuilder::new(BaseBuilder::new()) -/// .with_material(MaterialResource::new_ok(Default::default(), material)) +/// .with_material(MaterialResource::new_embedded(material)) /// .build(graph) /// } /// ``` diff --git a/fyrox-resource/src/lib.rs b/fyrox-resource/src/lib.rs index ed94fb24b..0d8df775e 100644 --- a/fyrox-resource/src/lib.rs +++ b/fyrox-resource/src/lib.rs @@ -760,37 +760,40 @@ mod tests { } } - const TEST_FOLDER: &'static str = "./test_output"; + const TEST_FOLDER1: &'static str = "./test_output1"; + const TEST_FOLDER2: &'static str = "./test_output2"; - fn make_file_path(n: usize) -> PathBuf { - Path::new(TEST_FOLDER).join(format!("test{n}.{}", MyDataLoader::EXT)) + fn make_file_path(root: &str, n: usize) -> PathBuf { + Path::new(root).join(format!("test{n}.{}", MyDataLoader::EXT)) } - fn make_metadata_file_path(n: usize) -> PathBuf { - Path::new(TEST_FOLDER).join(format!( + fn make_metadata_file_path(root: &str, n: usize) -> PathBuf { + Path::new(root).join(format!( "test{n}.{}.{}", MyDataLoader::EXT, ResourceMetadata::EXTENSION )) } - fn write_test_resources(indices: Range) { - let path = Path::new(TEST_FOLDER); + fn write_test_resources(root: &str, indices: Range) { + let path = Path::new(root); if !std::fs::exists(path).unwrap() { std::fs::create_dir_all(path).unwrap(); } for i in indices { - MyData { data: i as u32 }.save(&make_file_path(i)).unwrap(); + MyData { data: i as u32 } + .save(&make_file_path(root, i)) + .unwrap(); } } #[test] fn test_registry_scan() { - write_test_resources(0..2); + write_test_resources(TEST_FOLDER1, 0..2); - assert!(std::fs::exists(make_file_path(0)).unwrap()); - assert!(std::fs::exists(make_file_path(1)).unwrap()); + assert!(std::fs::exists(make_file_path(TEST_FOLDER1, 0)).unwrap()); + assert!(std::fs::exists(make_file_path(TEST_FOLDER1, 1)).unwrap()); let io = Arc::new(FsResourceIo); @@ -798,22 +801,27 @@ mod tests { loaders.set(MyDataLoader {}); let loaders = Arc::new(Mutex::new(loaders)); - let registry = block_on(ResourceRegistry::scan(io, loaders, TEST_FOLDER)); + let registry = block_on(ResourceRegistry::scan( + io, + loaders, + Path::new(TEST_FOLDER1).join("resources.registry"), + )); - assert!(std::fs::exists(make_metadata_file_path(0)).unwrap()); - assert!(std::fs::exists(make_metadata_file_path(1)).unwrap()); + assert!(std::fs::exists(make_metadata_file_path(TEST_FOLDER1, 0)).unwrap()); + assert!(std::fs::exists(make_metadata_file_path(TEST_FOLDER1, 1)).unwrap()); assert_eq!(registry.len(), 2); } #[test] fn test_resource_manager_request_simple() { - write_test_resources(2..4); + write_test_resources(TEST_FOLDER2, 2..4); let resource_manager = ResourceManager::new(Arc::new(TaskPool::new())); resource_manager.add_loader(MyDataLoader {}); - resource_manager.update_and_load_registry(ResourceRegistry::DEFAULT_PATH); - let path1 = make_file_path(2); - let path2 = make_file_path(3); + resource_manager + .update_and_load_registry(Path::new(TEST_FOLDER2).join("resources.registry")); + let path1 = make_file_path(TEST_FOLDER2, 2); + let path2 = make_file_path(TEST_FOLDER2, 3); let res1 = resource_manager.request::(path1); let res2 = resource_manager.request::(path2); assert_eq!(block_on(res1).unwrap().data_ref().data, 2); diff --git a/fyrox-resource/src/metadata.rs b/fyrox-resource/src/metadata.rs index bf5cfc32a..baba0d614 100644 --- a/fyrox-resource/src/metadata.rs +++ b/fyrox-resource/src/metadata.rs @@ -22,6 +22,8 @@ use crate::io::ResourceIo; use fyrox_core::{io::FileError, Uuid}; use ron::ser::PrettyConfig; use serde::{Deserialize, Serialize}; +use std::fs::File; +use std::io::Write; use std::path::Path; #[derive(Serialize, Deserialize)] @@ -38,7 +40,7 @@ impl ResourceMetadata { } } - pub async fn load_from_file( + pub async fn load_from_file_async( path: &Path, resource_io: &dyn ResourceIo, ) -> Result { @@ -52,14 +54,29 @@ impl ResourceMetadata { }) } - pub async fn save(&self, path: &Path, resource_io: &dyn ResourceIo) -> Result<(), FileError> { - let string = ron::ser::to_string_pretty(self, PrettyConfig::default()).map_err(|err| { + fn serialize(&self, path: &Path) -> Result { + ron::ser::to_string_pretty(self, PrettyConfig::default()).map_err(|err| { FileError::Custom(format!( "Unable to serialize resource metadata for {} resource! Reason: {}", path.display(), err )) - })?; + }) + } + + pub async fn save_async( + &self, + path: &Path, + resource_io: &dyn ResourceIo, + ) -> Result<(), FileError> { + let string = self.serialize(path)?; resource_io.write_file(path, string.into_bytes()).await } + + pub fn save_sync(&self, path: &Path) -> Result<(), FileError> { + let string = self.serialize(path)?; + let mut file = File::create(path)?; + file.write_all(string.as_bytes())?; + Ok(()) + } } diff --git a/fyrox-resource/src/registry.rs b/fyrox-resource/src/registry.rs index fbbb50de7..e39b46d7d 100644 --- a/fyrox-resource/src/registry.rs +++ b/fyrox-resource/src/registry.rs @@ -199,6 +199,15 @@ impl ResourceRegistry { replace_slashes(ret) } + pub fn write_metadata(&mut self, uuid: Uuid, path: impl AsRef) -> Result<(), FileError> { + ResourceMetadata::new_with_random_id().save_sync(&append_extension( + path.as_ref(), + ResourceMetadata::EXTENSION, + ))?; + self.register(uuid, path.as_ref().to_path_buf()); + Ok(()) + } + pub fn register(&mut self, uuid: Uuid, path: PathBuf) -> Option { self.paths.insert(uuid, path) } @@ -301,7 +310,7 @@ impl ResourceRegistry { let metadata_path = append_extension(&path, ResourceMetadata::EXTENSION); let metadata = - match ResourceMetadata::load_from_file(&metadata_path, &*resource_io).await { + match ResourceMetadata::load_from_file_async(&metadata_path, &*resource_io).await { Ok(metadata) => metadata, Err(err) => { warn!( @@ -312,7 +321,9 @@ impl ResourceRegistry { err ); let new_metadata = ResourceMetadata::new_with_random_id(); - if let Err(err) = new_metadata.save(&metadata_path, &*resource_io).await { + if let Err(err) = + new_metadata.save_async(&metadata_path, &*resource_io).await + { warn!( "Unable to save resource {} metadata. Reason: {:?}", path.display(), diff --git a/fyrox-sound/src/renderer/hrtf.rs b/fyrox-sound/src/renderer/hrtf.rs index c9ad5a296..cf2fcdce8 100644 --- a/fyrox-sound/src/renderer/hrtf.rs +++ b/fyrox-sound/src/renderer/hrtf.rs @@ -44,6 +44,7 @@ //! use fyrox_sound::renderer::Renderer; //! use std::path::{Path, PathBuf}; //! use hrtf::HrirSphere; +//! use fyrox_resource::untyped::ResourceKind; //! //! fn use_hrtf(context: &mut SoundContext) { //! // IRC_1002_C.bin is HRIR sphere in binary format, can be any valid HRIR sphere @@ -51,7 +52,7 @@ //! let hrir_path = PathBuf::from("examples/data/IRC_1002_C.bin"); //! let hrir_sphere = HrirSphere::from_file(&hrir_path, context::SAMPLE_RATE).unwrap(); //! -//! context.state().set_renderer(Renderer::HrtfRenderer(HrtfRenderer::new(HrirSphereResource::from_hrir_sphere(hrir_sphere, hrir_path.into())))); +//! context.state().set_renderer(Renderer::HrtfRenderer(HrtfRenderer::new(HrirSphereResource::from_hrir_sphere(hrir_sphere, ResourceKind::Embedded)))); //! } //! ``` //! diff --git a/fyrox-ui/src/style/mod.rs b/fyrox-ui/src/style/mod.rs index 4e3e6d435..0a53ca696 100644 --- a/fyrox-ui/src/style/mod.rs +++ b/fyrox-ui/src/style/mod.rs @@ -216,7 +216,6 @@ impl Visit for StyledProperty { /// # widget::WidgetBuilder, /// # Thickness, UserInterface, /// # }; -/// # use fyrox_resource::untyped::ResourceKind; /// # /// fn build_with_style(ui: &mut UserInterface) { /// // The context will use UI style by default. You can override it using `ui.set_style(..)`. @@ -228,7 +227,7 @@ impl Visit for StyledProperty { /// .with(Button::CORNER_RADIUS, 6.0f32) /// .with(Button::BORDER_THICKNESS, Thickness::uniform(3.0)); /// -/// ctx.style = StyleResource::new_ok(ResourceKind::Embedded, style); +/// ctx.style = StyleResource::new_embedded(style); /// /// // The button will have corner radius of 6.0 points and border thickness of 3.0 points on /// // each side. @@ -244,14 +243,13 @@ impl Visit for StyledProperty { /// style::{resource::StyleResource, Style}, /// Thickness, UserInterface, /// }; -/// use fyrox_resource::untyped::ResourceKind; /// /// fn apply_style(ui: &mut UserInterface) { /// let style = Style::light_style() /// .with(Button::CORNER_RADIUS, 3.0f32) /// .with(Button::BORDER_THICKNESS, Thickness::uniform(1.0)); /// -/// ui.set_style(StyleResource::new_ok(ResourceKind::Embedded, style)); +/// ui.set_style(StyleResource::new_embedded(style)); /// } /// ``` #[derive(Visit, Reflect, Default, Debug, TypeUuidProvider)]