From 20b34dde20d22f5bb53a3e6dbb86458f485cea4b Mon Sep 17 00:00:00 2001 From: Mark Moissette Date: Wed, 27 Dec 2023 13:14:13 +0100 Subject: [PATCH] feat(bevy_gltf_blueprints): improved error handling for clone_entity (#82) * feat(bevy_gltf_blueprints): improved error handling for clone_entity * you will now get component name for components that have not been registered & thus cannot be cloned * added a small example (in examples/bevy_gltf_blueprints/basic), just press 'U' at runtime to try to spawn an entity with unregistered components * closes #81 --- Cargo.lock | 2 +- crates/bevy_gltf_blueprints/Cargo.toml | 2 +- .../bevy_gltf_blueprints/src/clone_entity.rs | 36 ++++++++------ .../src/spawn_from_blueprints.rs | 10 ++-- .../basic/src/game/in_game.rs | 49 +++++++++++++++++++ .../basic/src/game/mod.rs | 1 + .../src/core/camera/camera_replace_proxies.rs | 39 ++++++++------- .../core/lighting/lighting_replace_proxies.rs | 23 ++++----- .../src/core/lighting/mod.rs | 13 ++--- .../nested_blueprints/src/test_components.rs | 3 -- 10 files changed, 114 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3de9b01..bf576a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -779,7 +779,7 @@ dependencies = [ [[package]] name = "bevy_gltf_blueprints" -version = "0.5.0" +version = "0.5.1" dependencies = [ "bevy", "bevy_gltf_components 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/crates/bevy_gltf_blueprints/Cargo.toml b/crates/bevy_gltf_blueprints/Cargo.toml index bd8f504..23478bc 100644 --- a/crates/bevy_gltf_blueprints/Cargo.toml +++ b/crates/bevy_gltf_blueprints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_gltf_blueprints" -version = "0.5.0" +version = "0.5.1" authors = ["Mark 'kaosat-dev' Moissette"] description = "Adds the ability to define Blueprints/Prefabs for [Bevy](https://bevyengine.org/) inside gltf files and spawn them in Bevy." homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" diff --git a/crates/bevy_gltf_blueprints/src/clone_entity.rs b/crates/bevy_gltf_blueprints/src/clone_entity.rs index 28336ab..07e94d8 100644 --- a/crates/bevy_gltf_blueprints/src/clone_entity.rs +++ b/crates/bevy_gltf_blueprints/src/clone_entity.rs @@ -18,29 +18,31 @@ impl CloneEntity { // - the source or destination entity do not exist fn clone_entity(self, world: &mut World) { let components = { - let registry = world.get_resource::().unwrap().read(); + let registry = world + .get_resource::() + .expect("the world should have a type registry") + .read(); world .get_entity(self.source) - .unwrap() + .expect("source entity should exist") .archetype() .components() .map(|component_id| { - world + let component_info = world .components() .get_info(component_id) - .unwrap() - .type_id() - .unwrap() - }) - .map(|type_id| { - // println!("type_id {:?}", type_id); - registry - .get(type_id) - .unwrap() - .data::() - .unwrap() - .clone() + .expect("component info should be available"); + + let type_id = component_info.type_id().unwrap(); + let type_id = registry.get(type_id).expect( + format!( + "cannot clone entity: component: {:?} is not registered", + component_info.name() + ) + .as_str(), + ); + return type_id.data::().unwrap().clone(); }) .collect::>() }; @@ -51,7 +53,9 @@ impl CloneEntity { .unwrap() .clone_value(); - let mut destination = world.get_entity_mut(self.destination).unwrap(); + let mut destination = world + .get_entity_mut(self.destination) + .expect("destination entity should exist"); component.apply_or_insert(&mut destination, &*source); } diff --git a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs index 6bc6b34..0baaaa0 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs @@ -49,12 +49,10 @@ pub(crate) fn spawn_from_blueprints( assets_gltf: Res>, asset_server: Res, blueprints_config: Res, - ) { for (entity, name, blupeprint_name, transform, original_parent) in spawn_placeholders.iter() { debug!("need to spawn {:?}, id: {:?}", blupeprint_name.0, entity); - let what = &blupeprint_name.0; let model_file_name = format!("{}.{}", &what, &blueprints_config.format); let model_path = @@ -63,8 +61,6 @@ pub(crate) fn spawn_from_blueprints( debug!("attempting to spawn {:?}", model_path); let model_handle: Handle = asset_server.load(model_path); - - let gltf = assets_gltf .get(&model_handle) .expect("this gltf should have been loaded"); @@ -97,12 +93,12 @@ pub(crate) fn spawn_from_blueprints( let world = game_world.single_mut(); let mut parent = world.1[0]; // FIXME: dangerous hack because our gltf data have a single child like this, but might not always be the case - + // ideally, insert the newly created entity as a child of the original parent, if any, the world otherwise if let Some(original_parent) = original_parent { parent = original_parent.get(); } - - commands.entity(parent).add_child(child_scene); + + commands.entity(parent).add_child(child_scene); } } diff --git a/examples/bevy_gltf_blueprints/basic/src/game/in_game.rs b/examples/bevy_gltf_blueprints/basic/src/game/in_game.rs index 2500bbb..86fa8de 100644 --- a/examples/bevy_gltf_blueprints/basic/src/game/in_game.rs +++ b/examples/bevy_gltf_blueprints/basic/src/game/in_game.rs @@ -40,6 +40,10 @@ pub fn setup_game( next_game_state.set(GameState::InGame) } +#[derive(Component, Reflect, Default, Debug)] +#[reflect(Component)] +struct UnregisteredComponent; + pub fn spawn_test( keycode: Res>, mut commands: Commands, @@ -83,3 +87,48 @@ pub fn spawn_test( commands.entity(world).add_child(new_entity); } } + +pub fn spawn_test_failing( + keycode: Res>, + mut commands: Commands, + + mut game_world: Query<(Entity, &Children), With>, +) { + if keycode.just_pressed(KeyCode::U) { + let world = game_world.single_mut(); + let world = world.1[0]; + + let mut rng = rand::thread_rng(); + let range = 5.5; + let x: f32 = rng.gen_range(-range..range); + let y: f32 = rng.gen_range(-range..range); + + let mut rng = rand::thread_rng(); + let range = 0.8; + let vel_x: f32 = rng.gen_range(-range..range); + let vel_y: f32 = rng.gen_range(2.0..2.5); + let vel_z: f32 = rng.gen_range(-range..range); + + let name_index: u64 = rng.gen(); + + let new_entity = commands + .spawn(( + BluePrintBundle { + blueprint: BlueprintName("Health_Pickup".to_string()), + transform: TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)), + ..Default::default() + }, + bevy::prelude::Name::from(format!("test{}", name_index)), + // BlueprintName("Health_Pickup".to_string()), + // SpawnHere, + // TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)), + Velocity { + linvel: Vec3::new(vel_x, vel_y, vel_z), + angvel: Vec3::new(0.0, 0.0, 0.0), + }, + UnregisteredComponent, + )) + .id(); + commands.entity(world).add_child(new_entity); + } +} diff --git a/examples/bevy_gltf_blueprints/basic/src/game/mod.rs b/examples/bevy_gltf_blueprints/basic/src/game/mod.rs index a650314..67716de 100644 --- a/examples/bevy_gltf_blueprints/basic/src/game/mod.rs +++ b/examples/bevy_gltf_blueprints/basic/src/game/mod.rs @@ -104,6 +104,7 @@ impl Plugin for GamePlugin { player_move_demo, //.run_if(in_state(AppState::Running)), // test_collision_events spawn_test, + spawn_test_failing, ) .run_if(in_state(GameState::InGame)), ) diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/src/core/camera/camera_replace_proxies.rs b/examples/bevy_gltf_blueprints/basic_scene_components/src/core/camera/camera_replace_proxies.rs index 49b0c10..76c8602 100644 --- a/examples/bevy_gltf_blueprints/basic_scene_components/src/core/camera/camera_replace_proxies.rs +++ b/examples/bevy_gltf_blueprints/basic_scene_components/src/core/camera/camera_replace_proxies.rs @@ -6,16 +6,23 @@ use bevy::prelude::*; use super::CameraTrackingOffset; - #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] pub struct SSAOSettings; pub fn camera_replace_proxies( mut commands: Commands, - mut added_cameras: Query<(Entity, &mut Camera, Option<&BloomSettings>, Option<&SSAOSettings>), (Added, With)>, + mut added_cameras: Query< + ( + Entity, + &mut Camera, + Option<&BloomSettings>, + Option<&SSAOSettings>, + ), + (Added, With), + >, - added_bloom_settings : Query<&BloomSettings, Added>, + added_bloom_settings: Query<&BloomSettings, Added>, added_ssao_settings: Query<&SSAOSettings, Added>, // Move to camera ) { for (entity, mut camera, bloom_settings, ssao_setting) in added_cameras.iter_mut() { @@ -24,27 +31,25 @@ pub fn camera_replace_proxies( commands .entity(entity) .insert(DebandDither::Enabled) - .insert(Tonemapping::BlenderFilmic) - ; + .insert(Tonemapping::BlenderFilmic); // we only inject the scene_level bloom settings if there are no settings already on the Camera if bloom_settings.is_none() { - for bloom_settings in added_bloom_settings.iter(){ - commands - .entity(entity) - .insert(BloomSettings { - intensity: bloom_settings.intensity, - composite_mode: BloomCompositeMode::Additive, - ..default() - }); + for bloom_settings in added_bloom_settings.iter() { + commands.entity(entity).insert(BloomSettings { + intensity: bloom_settings.intensity, + composite_mode: BloomCompositeMode::Additive, + ..default() + }); } } - + if ssao_setting.is_none() { - for _ in added_ssao_settings.iter(){ + for _ in added_ssao_settings.iter() { commands.insert_resource(Msaa::Off); // when using SSAO, you cannot use Msaa - - commands.entity(entity) + + commands + .entity(entity) .insert(ScreenSpaceAmbientOcclusionBundle::default()) .insert(TemporalAntiAliasBundle::default()); } diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/lighting_replace_proxies.rs b/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/lighting_replace_proxies.rs index a92db65..aec4743 100644 --- a/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/lighting_replace_proxies.rs +++ b/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/lighting_replace_proxies.rs @@ -2,23 +2,26 @@ use bevy::prelude::*; use bevy::pbr::{CascadeShadowConfig, CascadeShadowConfigBuilder, DirectionalLightShadowMap}; +#[derive(Component, Reflect, Default, Debug)] +#[reflect(Component)] +pub struct AmbientLightSettings { + pub color: Color, + pub brightness: f32, +} #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] -pub struct AmbientLightSettings {pub color: Color, pub brightness: f32} - -#[derive(Component, Reflect, Default, Debug)] -#[reflect(Component)] -pub struct ShadowmapSettings {pub size: usize} - +pub struct ShadowmapSettings { + pub size: usize, +} pub fn lighting_replace_proxies( mut added_dirights: Query<(Entity, &mut DirectionalLight), Added>, mut added_spotlights: Query<&mut SpotLight, Added>, mut added_pointlights: Query<&mut PointLight, Added>, - added_ambient_proxies : Query<&AmbientLightSettings, Added>, - added_shadowmap_settings : Query<&ShadowmapSettings, Added>, + added_ambient_proxies: Query<&AmbientLightSettings, Added>, + added_shadowmap_settings: Query<&ShadowmapSettings, Added>, mut commands: Commands, ) { @@ -42,12 +45,11 @@ pub fn lighting_replace_proxies( light.shadows_enabled = true; } - for setting in added_shadowmap_settings.iter() { commands.insert_resource(DirectionalLightShadowMap { size: setting.size }); } - for ambient in added_ambient_proxies.iter(){ + for ambient in added_ambient_proxies.iter() { commands.insert_resource(AmbientLight { color: ambient.color, brightness: ambient.brightness, @@ -55,5 +57,4 @@ pub fn lighting_replace_proxies( // FIXME: does this belong here ? commands.insert_resource(ClearColor(ambient.color * ambient.brightness)); } - } diff --git a/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/mod.rs b/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/mod.rs index 50177de..237dafa 100644 --- a/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/mod.rs +++ b/examples/bevy_gltf_blueprints/basic_scene_components/src/core/lighting/mod.rs @@ -7,13 +7,10 @@ use bevy::prelude::*; pub struct LightingPlugin; impl Plugin for LightingPlugin { fn build(&self, app: &mut App) { - app - .register_type::() - .register_type::() - // FIXME: adding these since they are missing - .register_type::() - - .add_systems(PreUpdate, lighting_replace_proxies) - ; + app.register_type::() + .register_type::() + // FIXME: adding these since they are missing + .register_type::() + .add_systems(PreUpdate, lighting_replace_proxies); } } diff --git a/examples/bevy_gltf_blueprints/nested_blueprints/src/test_components.rs b/examples/bevy_gltf_blueprints/nested_blueprints/src/test_components.rs index 4da1595..01635e0 100644 --- a/examples/bevy_gltf_blueprints/nested_blueprints/src/test_components.rs +++ b/examples/bevy_gltf_blueprints/nested_blueprints/src/test_components.rs @@ -4,7 +4,6 @@ use bevy::prelude::*; #[reflect(Component)] struct Marker; - #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] struct Enemy; @@ -13,7 +12,6 @@ struct Enemy; #[reflect(Component)] struct NestingTest; - #[derive(Component, Reflect, Default, Debug, Deref, DerefMut)] #[reflect(Component)] struct TuppleTestF32(f32); @@ -77,7 +75,6 @@ impl Plugin for ComponentsTestPlugin { .register_type::() .register_type::() .register_type::() - .register_type::() .register_type::() .register_type::()