diff --git a/crates/blenvy/Cargo.toml b/crates/blenvy/Cargo.toml index dbf7803..3d4c758 100644 --- a/crates/blenvy/Cargo.toml +++ b/crates/blenvy/Cargo.toml @@ -14,7 +14,7 @@ license = "MIT OR Apache-2.0" workspace = true [dependencies] -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "file_watcher"] } +bevy = { version = "0.14", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "file_watcher"] } serde = "1.0.188" ron = "0.8.1" serde_json = "1.0.108" @@ -34,4 +34,4 @@ gltf = { version = "1.4.0", default-features = false, features = [ [dev-dependencies] -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file +bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/blenvy/src/blueprints/materials.rs b/crates/blenvy/src/blueprints/materials.rs index 3bac80f..7585f1c 100644 --- a/crates/blenvy/src/blueprints/materials.rs +++ b/crates/blenvy/src/blueprints/materials.rs @@ -57,7 +57,7 @@ pub(crate) fn inject_materials( let model_handle: Handle = asset_server.load(material_info.path.clone()); // FIXME: kinda weird now let mat_gltf = assets_gltf .get(model_handle.id()) - .expect("material should have been preloaded"); + .expect(&format!("materials file {} should have been preloaded", material_info.path)); if mat_gltf.named_materials.contains_key(&material_info.name as &str) { let material = mat_gltf .named_materials diff --git a/crates/blenvy/src/blueprints/spawn_from_blueprints.rs b/crates/blenvy/src/blueprints/spawn_from_blueprints.rs index 299f39e..38eee3c 100644 --- a/crates/blenvy/src/blueprints/spawn_from_blueprints.rs +++ b/crates/blenvy/src/blueprints/spawn_from_blueprints.rs @@ -60,6 +60,12 @@ pub struct AddToGameWorld; pub(crate) struct OriginalChildren(pub Vec); +#[derive(Component)] +/// You can add this component to a blueprint instance, and the instance will be hidden until it is ready +/// You usually want to use this for worlds/level spawning , or dynamic spawning at runtime, but not when you are adding blueprint instances to an existing entity +/// as it would first become invisible before re-appearing again +pub struct HideUntilReady; + #[derive(Event, Debug)] pub enum BlueprintEvent { @@ -261,6 +267,7 @@ pub(crate) fn blueprints_assets_ready(spawn_placeholders: Query< Option<&Parent>, Option<&AddToGameWorld>, Option<&Name>, + Option<&HideUntilReady> ), ( With, @@ -283,6 +290,7 @@ pub(crate) fn blueprints_assets_ready(spawn_placeholders: Query< original_parent, add_to_world, name, + hide_until_ready, ) in spawn_placeholders.iter() { /*info!( @@ -336,8 +344,6 @@ pub(crate) fn blueprints_assets_ready(spawn_placeholders: Query< SceneBundle { scene: scene.clone(), transform: transforms, - visibility: Visibility::Hidden, - ..Default::default() }, OriginalChildren(original_children), @@ -345,15 +351,19 @@ pub(crate) fn blueprints_assets_ready(spawn_placeholders: Query< // these are animations specific to the inside of the blueprint named_animations: named_animations//gltf.named_animations.clone(), }, - )); - /* if add_to_world.is_some() { + if hide_until_ready.is_some() { + commands.entity(entity).insert(Visibility::Hidden); // visibility: + } + + // only allow automatically adding a newly spawned blueprint instance to the "world", if the entity does not have a parent + if add_to_world.is_some() && original_parent.is_some() { let world = game_world .get_single_mut() .expect("there should be a game world present"); commands.entity(world).add_child(entity); - } */ + } } } @@ -382,8 +392,6 @@ pub struct BlueprintChildrenReady; #[reflect(Component)] pub struct BlueprintReadyForPostProcess; - -// TODO: disregard blueprints that have been spawned WAIT , we already have BlueprintSpawning pub(crate) fn blueprints_scenes_spawned( spawned_blueprint_scene_instances: Query<(Entity, Option<&Name>, Option<&Children>, Option<&SpawnTrackRoot>), (With, Added)>, with_blueprint_infos : Query<(Entity, Option<&Name>), With>, @@ -396,7 +404,6 @@ pub(crate) fn blueprints_scenes_spawned( mut commands: Commands, all_names: Query<&Name> - ) { for (entity, name, children, track_root) in spawned_blueprint_scene_instances.iter(){ info!("Done spawning blueprint scene for entity named {:?} (track root: {:?})", name, track_root); @@ -405,34 +412,59 @@ pub(crate) fn blueprints_scenes_spawned( let mut tracker_data: HashMap = HashMap::new(); - for parent in all_parents.iter_ancestors(entity) { - if with_blueprint_infos.get(parent).is_ok() { + if track_root.is_none() { + for parent in all_parents.iter_ancestors(entity) { + if with_blueprint_infos.get(parent).is_ok() { + + println!("found a parent with blueprint_info {:?} for {:?}", all_names.get(parent), all_names.get(entity)); + commands.entity(entity).insert(SpawnTrackRoot(parent));// Injecting to know which entity is the root - println!("found a parent with blueprint_info {:?} for {:?}", all_names.get(parent), all_names.get(entity)); - break; + break; + } } } + if children.is_some() { for child in all_children.iter_descendants(entity) { if with_blueprint_infos.get(child).is_ok() { - sub_blueprint_instances.push(child); - if let Ok(nname) = all_names.get(child) { - sub_blueprint_instance_names.push(nname.clone()); - } + // println!("Parent blueprint instance of {:?} is {:?}", all_names.get(child), all_names.get(entity)); - tracker_data.insert(child, false); - if track_root.is_some() { - let prev_root = track_root.unwrap().0; - // if we already had a track root, and it is different from the current entity , change the previous track root's list of children - if prev_root != entity { - let mut tracker = sub_blueprint_trackers.get_mut(prev_root).expect("should have a tracker"); - tracker.1.sub_blueprint_instances.remove(&child); + + + for parent in all_parents.iter_ancestors(child) { + if with_blueprint_infos.get(parent).is_ok() { + + if parent == entity { + //println!("yohoho"); + println!("Parent blueprint instance of {:?} is {:?}", all_names.get(child), all_names.get(parent)); + + commands.entity(child).insert(SpawnTrackRoot(entity));// Injecting to know which entity is the root + + tracker_data.insert(child, false); + + sub_blueprint_instances.push(child); + if let Ok(nname) = all_names.get(child) { + sub_blueprint_instance_names.push(nname.clone()); + } + + /*if track_root.is_some() { + let prev_root = track_root.unwrap().0; + // if we already had a track root, and it is different from the current entity , change the previous track root's list of children + if prev_root != entity { + let mut tracker = sub_blueprint_trackers.get_mut(prev_root).expect("should have a tracker"); + tracker.1.sub_blueprint_instances.remove(&child); + } + }*/ + + } + break; } } - - commands.entity(child).insert(SpawnTrackRoot(entity));// Injecting to know which entity is the root + + + } } } @@ -481,7 +513,7 @@ pub(crate) fn blueprints_transfer_components( ) { for (original, children, original_children, name, track_root) in foo.iter() { - println!("YOOO ready !! {:?}", name); + info!("YOOO ready !! removing empty nodes {:?}", name); if children.len() == 0 { warn!("timing issue ! no children found, please restart your bevy app (bug being investigated)"); @@ -515,7 +547,7 @@ pub(crate) fn blueprints_transfer_components( } commands.entity(original) - .insert(BlueprintReadyForPostProcess); // Tag the entity so any systems dealing with post processing can now it is now their "turn" + .insert(BlueprintReadyForPostProcess); // Tag the entity so any systems dealing with post processing can know it is now their "turn" // commands.entity(original).remove::>(); // FIXME: if we delete the handle to the scene, things get despawned ! not what we want //commands.entity(original).remove::(); // also clear the sub assets tracker to free up handles, perhaps just freeing up the handles and leave the rest would be better ? //commands.entity(original).remove::(); @@ -524,6 +556,7 @@ pub(crate) fn blueprints_transfer_components( // now check if the current entity is a child blueprint instance of another entity // this should always be done last, as children should be finished before the parent can be processed correctly + // TODO: perhaps use observers for these if let Some(track_root) = track_root { let root_name = all_names.get(track_root.0); println!("got some root {:?}", root_name); @@ -555,19 +588,23 @@ pub(crate) fn blueprints_transfer_components( pub struct BlueprintReadyForFinalizing; pub(crate) fn blueprints_finalize_instances( - blueprint_instances: Query<(Entity, Option<&Name>, &BlueprintInfo), (With, With)>, + blueprint_instances: Query<(Entity, Option<&Name>, &BlueprintInfo, Option<&HideUntilReady>), (With, With)>, mut blueprint_events: EventWriter, mut commands: Commands, ) { - for (entity, name, blueprint_info) in blueprint_instances.iter() { + for (entity, name, blueprint_info, hide_until_ready) in blueprint_instances.iter() { info!("Finalizing blueprint instance {:?}", name); commands.entity(entity) .remove::() .remove::() .remove::() .insert(BlueprintInstanceReady) - .insert(Visibility::Visible) ; + if hide_until_ready.is_some() { + println!("REVEAAAL"); + commands.entity(entity).insert(Visibility::Visible); + } + blueprint_events.send(BlueprintEvent::InstanceReady {entity: entity, blueprint_name: blueprint_info.name.clone(), blueprint_path: blueprint_info.path.clone()}); } diff --git a/testing/bevy_example/Cargo.toml b/testing/bevy_example/Cargo.toml index db71fce..80f6e33 100644 --- a/testing/bevy_example/Cargo.toml +++ b/testing/bevy_example/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -bevy = { version = "0.14.0-rc.3", features = ["dynamic_linking"] } +bevy = { version = "0.14", features = ["dynamic_linking"] } blenvy = { path = "../../crates/blenvy" } # bevy_gltf_blueprints = { path = "../../crates/bevy_gltf_blueprints" } # bevy_registry_export = { path = "../../crates/bevy_registry_export" } diff --git a/testing/bevy_example/art/testing.blend b/testing/bevy_example/art/testing.blend index 43050c0..24db140 100644 Binary files a/testing/bevy_example/art/testing.blend and b/testing/bevy_example/art/testing.blend differ diff --git a/testing/bevy_example/assets/registry.json b/testing/bevy_example/assets/registry.json index 6df0ddf..cc7c361 100644 --- a/testing/bevy_example/assets/registry.json +++ b/testing/bevy_example/assets/registry.json @@ -4182,6 +4182,30 @@ "type": "object", "typeInfo": "Struct" }, + "bevy_example::test_components::RedirectPropHitImpulse": { + "isComponent": true, + "isResource": false, + "long_name": "bevy_example::test_components::RedirectPropHitImpulse", + "oneOf": [ + { + "items": false, + "long_name": "Local", + "prefixItems": [ + { + "type": { + "$ref": "#/$defs/glam::Vec3" + } + } + ], + "short_name": "Local", + "type": "array", + "typeInfo": "Tuple" + } + ], + "short_name": "RedirectPropHitImpulse", + "type": "object", + "typeInfo": "Enum" + }, "bevy_example::test_components::TupleTest2": { "isComponent": true, "isResource": false, @@ -8145,11 +8169,6 @@ "$ref": "#/$defs/bevy_render::alpha::AlphaMode" } }, - "anisotropy_channel": { - "type": { - "$ref": "#/$defs/bevy_pbr::pbr_material::UvChannel" - } - }, "anisotropy_rotation": { "type": { "$ref": "#/$defs/f32" @@ -8160,11 +8179,6 @@ "$ref": "#/$defs/f32" } }, - "anisotropy_texture": { - "type": { - "$ref": "#/$defs/core::option::Option>" - } - }, "attenuation_color": { "type": { "$ref": "#/$defs/bevy_color::color::Color" @@ -8374,7 +8388,6 @@ "clearcoat_perceptual_roughness", "anisotropy_strength", "anisotropy_rotation", - "anisotropy_channel", "double_sided", "unlit", "fog_enabled", diff --git a/testing/bevy_example/src/game/in_game.rs b/testing/bevy_example/src/game/in_game.rs index cbd5d0d..e84ccda 100644 --- a/testing/bevy_example/src/game/in_game.rs +++ b/testing/bevy_example/src/game/in_game.rs @@ -1,5 +1,5 @@ use bevy::prelude::*; -use blenvy::{BluePrintBundle, BlueprintInfo, DynamicBlueprintInstance, GameWorldTag, SpawnHere}; +use blenvy::{BluePrintBundle, BlueprintInfo, DynamicBlueprintInstance, GameWorldTag, HideUntilReady, SpawnHere}; use crate::{GameState, InAppRunning}; //use bevy_rapier3d::prelude::Velocity; @@ -23,6 +23,7 @@ pub fn setup_game( commands.spawn(( BlueprintInfo{name: "World".into(), path: "levels/World.glb".into()}, + HideUntilReady, bevy::prelude::Name::from("world"), //FIXME: not really needed ? could be infered from blueprint's name/ path SpawnHere, GameWorldTag, @@ -67,6 +68,7 @@ pub fn spawn_test( }, DynamicBlueprintInstance, bevy::prelude::Name::from(format!("test{}", name_index)), + HideUntilReady, // SpawnHere, TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)), /*Velocity { diff --git a/testing/bevy_example/src/game/mod.rs b/testing/bevy_example/src/game/mod.rs index f1bf8e7..51dd016 100644 --- a/testing/bevy_example/src/game/mod.rs +++ b/testing/bevy_example/src/game/mod.rs @@ -129,10 +129,19 @@ fn exit_game(mut app_exit_events: ResMut>) { fn check_for_gltf_events( mut blueprint_events: EventReader, + all_names: Query<&Name>, ) { for event in blueprint_events.read() { - info!("BLUEPRINT EVENT: {:?}", event); + match event { + BlueprintEvent::InstanceReady{entity, blueprint_name, blueprint_path} => { + info!("BLUEPRINT EVENT: {:?} for {:?}", event, all_names.get(*entity)); + + } + _=> { + info!("BLUEPRINT EVENT: {:?}", event); + } + } } } diff --git a/testing/bevy_example/src/hierarchy_debug.rs b/testing/bevy_example/src/hierarchy_debug.rs index f63ee7a..c3c086a 100644 --- a/testing/bevy_example/src/hierarchy_debug.rs +++ b/testing/bevy_example/src/hierarchy_debug.rs @@ -1,7 +1,7 @@ use bevy::{gltf::{GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras}, prelude::*}; use blenvy::{BlueprintAssets, BlueprintInstanceReady}; -use crate::{BasicTest, EnumComplex}; +use crate::{BasicTest, EnumComplex, RedirectPropHitImpulse}; #[derive(Component)] pub struct HiearchyDebugTag; @@ -12,7 +12,7 @@ pub fn setup_hierarchy_debug(mut commands: Commands, asset_server: Res, - all_names:&Query<&Name>, root: &Entity, + all_names:&Query<&Name>, + root: &Entity, + all_transforms: &Query<&Transform>, + all_global_transforms: &Query<&GlobalTransform>, nesting: usize, to_check: &Query<&BasicTest>//&Query<(&BlueprintInstanceReady, &BlueprintAssets)>, ) @@ -48,14 +51,14 @@ pub fn get_descendants( let components_to_check = to_check.get(*root); - hierarchy_display.push( format!("{}{} ({:?})", " ".repeat(nesting), name, components_to_check) ); // + hierarchy_display.push( format!("{}{} ({:?}) ({:?})", " ".repeat(nesting), name, all_transforms.get(*root), all_global_transforms.get(*root)) ); //components_to_check ({:?}) if let Ok(children) = all_children.get(*root) { for child in children.iter() { - let child_descendants_display = get_descendants(&all_children, &all_names, &child, nesting + 4, &to_check); + let child_descendants_display = get_descendants(&all_children, &all_names, &child, &all_transforms, &all_global_transforms, nesting + 4, &to_check); hierarchy_display.push(child_descendants_display); } } @@ -66,6 +69,8 @@ pub fn draw_hierarchy_debug( root: Query<(Entity, Option<&Name>, &Children), (Without)>, all_children: Query<&Children>, all_names:Query<&Name>, + all_transforms: Query<&Transform>, + all_global_transforms: Query<&GlobalTransform>, to_check: Query<&BasicTest>,//Query<(&BlueprintInstanceReady, &BlueprintAssets)>, mut display: Query<&mut Text, With>, @@ -75,7 +80,7 @@ pub fn draw_hierarchy_debug( for (root_entity, name, children) in root.iter() { // hierarchy_display.push( format!("Hierarchy root{:?}", name) ); - hierarchy_display.push(get_descendants(&all_children, &all_names, &root_entity, 0, &to_check)); + hierarchy_display.push(get_descendants(&all_children, &all_names, &root_entity, &all_transforms, &all_global_transforms, 0, &to_check)); // let mut children = all_children.get(root_entity); /*for child in children.iter() { // hierarchy_display @@ -134,13 +139,13 @@ for (id, name, scene_extras, extras, mesh_extras, material_extras) in } fn check_for_component( - foo: Query<(Entity, Option<&Name>, &EnumComplex)>, + foo: Query<(Entity, Option<&Name>, &RedirectPropHitImpulse)>, mut display: Query<&mut Text, With>, ){ let mut info_lines: Vec = vec![]; for (entiity, name , enum_complex) in foo.iter(){ - let data = format!(" We have a 'EnumComplex' component: {:?} (on {:?})", enum_complex, name); + let data = format!(" We have a matching component: {:?} (on {:?})", enum_complex, name); info_lines.push(data); println!("yoho component"); @@ -156,8 +161,8 @@ impl Plugin for HiearchyDebugPlugin { fn build(&self, app: &mut App) { app .add_systems(Startup, setup_hierarchy_debug) - // .add_systems(Update, check_for_component) - .add_systems(Update, draw_hierarchy_debug) + //.add_systems(Update, check_for_component) + //.add_systems(Update, draw_hierarchy_debug) //.add_systems(Update, check_for_gltf_extras) ; diff --git a/testing/bevy_example/src/test_components.rs b/testing/bevy_example/src/test_components.rs index 47362ff..5f8e16c 100644 --- a/testing/bevy_example/src/test_components.rs +++ b/testing/bevy_example/src/test_components.rs @@ -224,6 +224,12 @@ pub struct ComponentWithFieldsOfIdenticalType{ #[reflect(Component)] pub struct ComponentWithFieldsOfIdenticalType2(f32, f32, f32); + +#[derive(Debug, Clone, Copy, PartialEq, Reflect, Component)] +#[reflect(Component, )] +pub enum RedirectPropHitImpulse { + Local(Vec3), +} pub struct ComponentsTestPlugin; impl Plugin for ComponentsTestPlugin { fn build(&self, app: &mut App) { @@ -279,6 +285,8 @@ impl Plugin for ComponentsTestPlugin { .register_type::() .register_type::() + .register_type::() + .add_plugins(MaterialPlugin::< ExtendedMaterial, >::default());