feat(bevy_registry_export): added boilerplate to make registry path relative to assets folder

* for bevy_gltf_components: registered GltfProcessed component (supresses a few warnings etc)
 * for the rest: cargo fmt
This commit is contained in:
kaosat.dev 2024-02-29 23:38:55 +01:00
parent a705a238fd
commit 7f824c47fe
6 changed files with 71 additions and 38 deletions

View File

@ -30,11 +30,14 @@ pub struct MaterialInfo {
pub(crate) fn materials_inject( pub(crate) fn materials_inject(
mut blueprints_config: ResMut<BluePrintsConfig>, mut blueprints_config: ResMut<BluePrintsConfig>,
material_infos: Query<(&MaterialInfo, &Children), Added<MaterialInfo>>, material_infos: Query<(&MaterialInfo, &Children), Added<MaterialInfo>>,
with_materials_and_meshes: Query<(), ( with_materials_and_meshes: Query<
With<Parent>, (),
With<Handle<StandardMaterial>>, (
With<Handle<Mesh>>, With<Parent>,
)>, With<Handle<StandardMaterial>>,
With<Handle<Mesh>>,
),
>,
models: Res<Assets<bevy::gltf::Gltf>>, models: Res<Assets<bevy::gltf::Gltf>>,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,

View File

@ -8,8 +8,9 @@ pub mod process_gltfs;
pub use process_gltfs::*; pub use process_gltfs::*;
use bevy::{ use bevy::{
ecs::system::Resource, ecs::{component::Component, reflect::ReflectComponent, system::Resource},
prelude::{App, IntoSystemConfigs, Plugin, SystemSet, Update}, prelude::{App, IntoSystemConfigs, Plugin, SystemSet, Update},
reflect::Reflect,
}; };
/// A Bevy plugin for extracting components from gltf files and automatically adding them to the relevant entities /// A Bevy plugin for extracting components from gltf files and automatically adding them to the relevant entities
@ -45,6 +46,11 @@ use bevy::{
///} ///}
/// ``` /// ```
/// this is a flag component to tag a processed gltf, to avoid processing things multiple times
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
pub struct GltfProcessed;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
/// systemset to order your systems after the component injection when needed /// systemset to order your systems after the component injection when needed
pub enum GltfComponentsSet { pub enum GltfComponentsSet {
@ -68,12 +74,13 @@ impl Default for ComponentsFromGltfPlugin {
impl Plugin for ComponentsFromGltfPlugin { impl Plugin for ComponentsFromGltfPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_resource(GltfComponentsConfig { app.register_type::<GltfProcessed>()
legacy_mode: self.legacy_mode, .insert_resource(GltfComponentsConfig {
}) legacy_mode: self.legacy_mode,
.add_systems( })
Update, .add_systems(
(add_components_from_gltf_extras).in_set(GltfComponentsSet::Injection), Update,
); (add_components_from_gltf_extras).in_set(GltfComponentsSet::Injection),
);
} }
} }

View File

@ -5,7 +5,6 @@ use bevy::{
query::{Added, Without}, query::{Added, Without},
reflect::{AppTypeRegistry, ReflectComponent}, reflect::{AppTypeRegistry, ReflectComponent},
world::World, world::World,
component::Component
}, },
gltf::GltfExtras, gltf::GltfExtras,
hierarchy::Parent, hierarchy::Parent,
@ -14,11 +13,7 @@ use bevy::{
utils::HashMap, utils::HashMap,
}; };
use crate::{ronstring_to_reflect_component, GltfComponentsConfig}; use crate::{ronstring_to_reflect_component, GltfComponentsConfig, GltfProcessed};
/// this is a flag component to tag a processed gltf, to avoid processing things multiple times
#[derive(Component)]
pub struct GltfProcessed;
/// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection /// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection
pub fn add_components_from_gltf_extras(world: &mut World) { pub fn add_components_from_gltf_extras(world: &mut World) {
@ -37,7 +32,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
let type_registry: &AppTypeRegistry = world.resource(); let type_registry: &AppTypeRegistry = world.resource();
let type_registry = type_registry.read(); let type_registry = type_registry.read();
let reflect_components = ronstring_to_reflect_component( let reflect_components = ronstring_to_reflect_component(
&extra.value, &extra.value,
&type_registry, &type_registry,
@ -81,7 +76,7 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
if !components.is_empty() { if !components.is_empty() {
debug!("--entity {:?}, components {}", entity, components.len()); debug!("--entity {:?}, components {}", entity, components.len());
} }
for (component, type_registration) in components { for (component, type_registration) in components {
debug!( debug!(
"------adding {} {:?}", "------adding {} {:?}",
component.get_represented_type_info().unwrap().type_path(), component.get_represented_type_info().unwrap().type_path(),
@ -91,13 +86,12 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
{ {
let mut entity_mut = world.entity_mut(entity); let mut entity_mut = world.entity_mut(entity);
type_registration type_registration
.data::<ReflectComponent>() .data::<ReflectComponent>()
.expect("Unable to reflect component") .expect("Unable to reflect component")
.insert(&mut entity_mut, &*component, &type_registry); .insert(&mut entity_mut, &*component, &type_registry);
entity_mut.insert(GltfProcessed); // this is how can we insert any additional components entity_mut.insert(GltfProcessed); // this is how can we insert any additional components
} }
} }
} }
} }

View File

@ -113,7 +113,8 @@ pub fn ronstring_to_reflect_component(
println!("serialized Component {}", serialized);*/ println!("serialized Component {}", serialized);*/
debug!("component data ron string {}", ron_string); debug!("component data ron string {}", ron_string);
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()).expect("deserialzer should have been generated from string"); let mut deserializer = ron::Deserializer::from_str(ron_string.as_str())
.expect("deserialzer should have been generated from string");
let reflect_deserializer = UntypedReflectDeserializer::new(type_registry); let reflect_deserializer = UntypedReflectDeserializer::new(type_registry);
let component = reflect_deserializer let component = reflect_deserializer
.deserialize(&mut deserializer) .deserialize(&mut deserializer)

View File

@ -1,4 +1,4 @@
use std::fs::File; use std::{fs::File, path::Path};
use bevy::log::info; use bevy::log::info;
use bevy_ecs::{ use bevy_ecs::{
@ -8,14 +8,17 @@ use bevy_ecs::{
use bevy_reflect::{TypeInfo, TypeRegistration, VariantInfo}; // TypePath // DynamicTypePath use bevy_reflect::{TypeInfo, TypeRegistration, VariantInfo}; // TypePath // DynamicTypePath
use serde_json::{json, Map, Value}; use serde_json::{json, Map, Value};
use crate::ExportComponentsConfig; use crate::{AssetRoot, ExportComponentsConfig};
pub fn export_types(world: &mut World) { pub fn export_types(world: &mut World) {
let config = world let config = world
.get_resource::<ExportComponentsConfig>() .get_resource::<ExportComponentsConfig>()
.expect("ExportComponentsConfig should exist at this stage"); .expect("ExportComponentsConfig should exist at this stage");
let writer = File::create(&config.save_path).expect("should have created schema file"); let asset_root = world.resource::<AssetRoot>();
let registry_save_path = Path::join(&asset_root.0, &config.save_path);
println!("registry_save_path {:?}", registry_save_path);
let writer = File::create(registry_save_path).expect("should have created schema file");
let types = world.resource_mut::<AppTypeRegistry>(); let types = world.resource_mut::<AppTypeRegistry>();
let types = types.read(); let types = types.read();

View File

@ -6,6 +6,7 @@ use bevy_ecs::system::Resource;
pub use export_types::*; pub use export_types::*;
use bevy::{ use bevy::{
asset::AssetPlugin,
prelude::{App, Plugin}, prelude::{App, Plugin},
scene::SceneFilter, scene::SceneFilter,
}; };
@ -29,20 +30,44 @@ pub struct ExportRegistryPlugin {
impl Default for ExportRegistryPlugin { impl Default for ExportRegistryPlugin {
fn default() -> Self { fn default() -> Self {
Self { Self {
component_filter: SceneFilter::default(), // unused for now component_filter: SceneFilter::default(), // unused for now
resource_filter: SceneFilter::default(), // unused for now resource_filter: SceneFilter::default(), // unused for now
save_path: PathBuf::from("assets/registry.json"), save_path: PathBuf::from("registry.json"), // relative to assets folder
} }
} }
} }
impl Plugin for ExportRegistryPlugin { impl Plugin for ExportRegistryPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.insert_resource(ExportComponentsConfig { app.register_asset_root()
save_path: self.save_path.clone(), .insert_resource(ExportComponentsConfig {
component_filter: self.component_filter.clone(), save_path: self.save_path.clone(),
resource_filter: self.resource_filter.clone(), component_filter: self.component_filter.clone(),
}) resource_filter: self.resource_filter.clone(),
.add_systems(Startup, export_types); })
.add_systems(Startup, export_types);
} }
} }
trait RegistryExportApp {
fn register_asset_root(&mut self) -> &mut Self;
}
impl RegistryExportApp for App {
fn register_asset_root(&mut self) -> &mut Self {
let asset_plugin = get_asset_plugin(self);
let path_str = asset_plugin.file_path.clone();
let path = PathBuf::from(path_str);
self.insert_resource(AssetRoot(path))
}
}
fn get_asset_plugin(app: &App) -> &AssetPlugin {
let asset_plugins: Vec<&AssetPlugin> = app.get_added_plugins();
asset_plugins.into_iter().next().expect(ASSET_ERROR)
}
const ASSET_ERROR: &str = "Bevy_registry_export requires access to the Bevy asset plugin. \
Please add `ExportRegistryPlugin` after `AssetPlugin`, which is commonly added as part of the `DefaultPlugins`";
#[derive(Debug, Clone, PartialEq, Eq, Hash, Resource)]
pub(crate) struct AssetRoot(pub(crate) PathBuf);