From 00bf600ccfdf65554f12fffc3df6adbaded3d0ac Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Tue, 18 Jun 2024 22:26:18 +0200 Subject: [PATCH] feat(Blenvy): updated (most) of the crates' code to bevy 0.14 (rc) * tweaked & changed code where relevant * also added support for the new gltf_xxx_extras in bevy_gltf_components * animation support needs an overhaul given the extensive changes in v0.14 (wip) * still a giant mess, but works * examples not yet updated, will get overhauled * testing project is now independant from the "common" example code: ie no debug ui, no physics, no bevy_asset_loader * testing project WORKS , even without any of the above, so asset loading (even if rough), is functional ! * added VERY rough hierarchy/ components debug to testing project to visualize things without bevy_editor_pls egui & co * related tweaks & changes --- crates/bevy_gltf_blueprints/Cargo.toml | 8 +- crates/bevy_gltf_blueprints/src/animation.rs | 6 +- .../src/copy_components.rs | 2 +- crates/bevy_gltf_blueprints/src/lib.rs | 5 +- crates/bevy_gltf_blueprints/src/materials.rs | 4 +- .../src/spawn_from_blueprints.rs | 21 ++- .../src/spawn_post_process.rs | 5 +- crates/bevy_gltf_components/Cargo.toml | 6 +- .../bevy_gltf_components/src/process_gltfs.rs | 113 ++++++++++---- .../src/ronstring_to_reflect_component.rs | 6 +- crates/bevy_gltf_save_load/Cargo.toml | 6 +- crates/bevy_gltf_save_load/src/saving.rs | 2 +- crates/bevy_registry_export/Cargo.toml | 10 +- crates/blenvy/Cargo.toml | 22 +++ crates/blenvy/src/blender_settings.rs | 8 + .../blenvy/src/blender_settings/lighting.rs | 97 ++++++++++++ crates/blenvy/src/lib.rs | 78 ++++++++++ crates/blenvy/src/process_gltfs.rs | 130 ++++++++++++++++ .../src/ronstring_to_reflect_component.rs | 134 ++++++++++++++++ crates/blenvy/src/utils.rs | 3 + testing/bevy_example/Cargo.toml | 8 +- testing/bevy_example/src/game/animation.rs | 3 +- testing/bevy_example/src/game/in_game.rs | 2 +- testing/bevy_example/src/game/mod.rs | 19 ++- testing/bevy_example/src/hierarchy_debug.rs | 146 ++++++++++++++++++ testing/bevy_example/src/main.rs | 12 +- testing/bevy_example/src/state.rs | 59 +++++++ 27 files changed, 840 insertions(+), 75 deletions(-) create mode 100644 crates/blenvy/Cargo.toml create mode 100644 crates/blenvy/src/blender_settings.rs create mode 100644 crates/blenvy/src/blender_settings/lighting.rs create mode 100644 crates/blenvy/src/lib.rs create mode 100644 crates/blenvy/src/process_gltfs.rs create mode 100644 crates/blenvy/src/ronstring_to_reflect_component.rs create mode 100644 crates/blenvy/src/utils.rs create mode 100644 testing/bevy_example/src/hierarchy_debug.rs create mode 100644 testing/bevy_example/src/state.rs diff --git a/crates/bevy_gltf_blueprints/Cargo.toml b/crates/bevy_gltf_blueprints/Cargo.toml index fbd0749..2933a84 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.10.0" +version = "0.11.0" authors = ["Mark 'kaosat-dev' Moissette"] description = "Adds the ability to define Blueprints/Prefabs for Bevy inside gltf files and spawn them in Bevy." homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" @@ -14,8 +14,8 @@ license = "MIT OR Apache-2.0" workspace = true [dependencies] -bevy_gltf_components = { version = "0.5", path = "../bevy_gltf_components" } -bevy = { version = "0.13", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] } +bevy_gltf_components = { version = "0.6", path = "../bevy_gltf_components" } +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] } [dev-dependencies] -bevy = { version = "0.13", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/bevy_gltf_blueprints/src/animation.rs b/crates/bevy_gltf_blueprints/src/animation.rs index b7472d5..6a61a65 100644 --- a/crates/bevy_gltf_blueprints/src/animation.rs +++ b/crates/bevy_gltf_blueprints/src/animation.rs @@ -73,6 +73,7 @@ pub struct AnimationMarkerReached { ///////////////////// +/* /// triggers events when a given animation marker is reached for INSTANCE animations pub fn trigger_instance_animation_markers_events( animation_infos: Query<( @@ -82,13 +83,15 @@ pub fn trigger_instance_animation_markers_events( &SceneAnimations, &AnimationInfos, )>, - animation_players: Query<&AnimationPlayer>, + animation_players: Query<(&AnimationPlayer)>, animation_clips: Res>, + animation_graphs: Res>, mut animation_marker_events: EventWriter, ) { for (entity, markers, link, animations, animation_infos) in animation_infos.iter() { let animation_player = animation_players.get(link.0).unwrap(); let animation_clip = animation_clips.get(animation_player.animation_clip()); + // animation_player.play(animation) if animation_clip.is_some() { // println!("Entity {:?} markers {:?}", entity, markers); @@ -215,3 +218,4 @@ pub fn trigger_blueprint_animation_markers_events( } } } +*/ \ No newline at end of file diff --git a/crates/bevy_gltf_blueprints/src/copy_components.rs b/crates/bevy_gltf_blueprints/src/copy_components.rs index e68cd3d..b2a12b5 100644 --- a/crates/bevy_gltf_blueprints/src/copy_components.rs +++ b/crates/bevy_gltf_blueprints/src/copy_components.rs @@ -1,4 +1,4 @@ -use bevy::ecs::system::Command; +use bevy::ecs::world::Command; use bevy::prelude::*; use std::any::TypeId; diff --git a/crates/bevy_gltf_blueprints/src/lib.rs b/crates/bevy_gltf_blueprints/src/lib.rs index 1bd4ef1..23f882a 100644 --- a/crates/bevy_gltf_blueprints/src/lib.rs +++ b/crates/bevy_gltf_blueprints/src/lib.rs @@ -176,12 +176,13 @@ impl Plugin for BlueprintsPlugin { .chain() .in_set(GltfBlueprintsSet::AfterSpawn), ) - .add_systems( + /* .add_systems( Update, ( trigger_instance_animation_markers_events, trigger_blueprint_animation_markers_events, ), - ); + )*/ + ; } } diff --git a/crates/bevy_gltf_blueprints/src/materials.rs b/crates/bevy_gltf_blueprints/src/materials.rs index c6235cf..37d3f5c 100644 --- a/crates/bevy_gltf_blueprints/src/materials.rs +++ b/crates/bevy_gltf_blueprints/src/materials.rs @@ -160,10 +160,10 @@ pub(crate) fn materials_inject2( let mat_gltf = assets_gltf .get(model_handle.id()) .expect("material should have been preloaded"); - if mat_gltf.named_materials.contains_key(&material_info.name) { + if mat_gltf.named_materials.contains_key(&material_info.name as &str) { let material = mat_gltf .named_materials - .get(&material_info.name) + .get(&material_info.name as &str) .expect("this material should have been loaded"); blueprints_config .material_library_cache diff --git a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs index 92ffc40..f3bd1df 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use bevy::{gltf::Gltf, prelude::*, utils::HashMap}; +use bevy::{gltf::Gltf, prelude::*, utils::hashbrown::HashMap}; use crate::{AllAssets, AssetsToLoad, AssetLoadTracker, BluePrintsConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded}; @@ -28,7 +28,7 @@ pub struct SpawnHere; pub struct Spawned; -#[derive(Component)] +#[derive(Component, Debug)] /// flag component added when a Blueprint instance ist Ready : ie : /// - its assets have loaded /// - it has finished spawning @@ -194,8 +194,13 @@ pub(crate) fn check_for_loaded2( println!("loading {}: // load state: {:?}", tracker.name, asset_server.load_state(asset_id)); // FIXME: hack for now - let failed = asset_server.load_state(asset_id) == bevy::asset::LoadState::Failed; - + let mut failed = false;// asset_server.load_state(asset_id) == bevy::asset::LoadState::Failed(_error); + match asset_server.load_state(asset_id) { + bevy::asset::LoadState::Failed(_) => { + failed = true + }, + _ => {} + } tracker.loaded = loaded || failed; if loaded || failed { loaded_amount += 1; @@ -295,6 +300,12 @@ pub(crate) fn spawn_from_blueprints2( original_children.push(*child); } } + + let mut named_animations:HashMap> = HashMap::new() ; + for (key, value) in gltf.named_animations.iter() { + named_animations.insert(key.to_string(), value.clone()); + } + commands.entity(entity).insert(( SceneBundle { scene: scene.clone(), @@ -306,7 +317,7 @@ pub(crate) fn spawn_from_blueprints2( OriginalChildren(original_children), BlueprintAnimations { // these are animations specific to the inside of the blueprint - named_animations: gltf.named_animations.clone(), + named_animations: named_animations//gltf.named_animations.clone(), }, )); diff --git a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs index 62eaac6..f3336bf 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs @@ -38,7 +38,7 @@ pub(crate) fn spawned_blueprint_post_process( for (original, children, original_children, animations, no_inblueprint, name) in unprocessed_entities.iter() { - debug!("post processing blueprint for entity {:?}", name); + info!("post processing blueprint for entity {:?}", name); if children.len() == 0 { warn!("timing issue ! no children found, please restart your bevy app (bug being investigated)"); @@ -94,9 +94,10 @@ pub(crate) fn spawned_blueprint_post_process( commands.entity(original).remove::(); commands.entity(original).remove::(); - commands.entity(original).remove::>(); + // 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::(); commands.entity(root_entity).despawn_recursive(); + info!("DONE WITH POST PROCESS"); } } diff --git a/crates/bevy_gltf_components/Cargo.toml b/crates/bevy_gltf_components/Cargo.toml index 2004d97..9933da8 100644 --- a/crates/bevy_gltf_components/Cargo.toml +++ b/crates/bevy_gltf_components/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_gltf_components" -version = "0.5.1" +version = "0.6.0" authors = ["Mark 'kaosat-dev' Moissette"] description = "Allows you to define Bevy components direclty inside gltf files and instanciate the components on the Bevy side." homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" @@ -14,9 +14,9 @@ license = "MIT OR Apache-2.0" workspace = true [dependencies] -bevy = { version = "0.13", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } serde = "1.0.188" ron = "0.8.1" [dev-dependencies] -bevy = { version = "0.13", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/bevy_gltf_components/src/process_gltfs.rs b/crates/bevy_gltf_components/src/process_gltfs.rs index 241015f..73bd6be 100644 --- a/crates/bevy_gltf_components/src/process_gltfs.rs +++ b/crates/bevy_gltf_components/src/process_gltfs.rs @@ -6,7 +6,7 @@ use bevy::{ reflect::{AppTypeRegistry, ReflectComponent}, world::World, }, - gltf::GltfExtras, + gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras}, hierarchy::Parent, log::debug, reflect::{Reflect, TypeRegistration}, @@ -15,10 +15,48 @@ use bevy::{ use crate::{ronstring_to_reflect_component, GltfProcessed}; +// , mut entity_components: HashMap, TypeRegistration)>> +fn find_entity_components(entity: Entity, name: &Name, parent: &Parent, reflect_components: Vec<(Box, TypeRegistration)>, entity_components: &HashMap, TypeRegistration)>>) -> (Entity, Vec<(Box, TypeRegistration)>){ + // we assign the components specified /xxx_components objects to their parent node + let mut target_entity = entity; + // if the node contains "components" or ends with "_pa" (ie add to parent), the components will not be added to the entity itself but to its parent + // this is mostly used for Blender collections + if name.as_str().contains("components") || name.as_str().ends_with("_pa") { + debug!("adding components to parent"); + target_entity = parent.get(); + } + debug!("adding to {:?}", target_entity); + + // if there where already components set to be added to this entity (for example when entity_data was refering to a parent), update the vec of entity_components accordingly + // this allows for example blender collection to provide basic ecs data & the instances to override/ define their own values + if entity_components.contains_key(&target_entity) { + let mut updated_components: Vec<(Box, TypeRegistration)> = Vec::new(); + let current_components = &entity_components[&target_entity]; + // first inject the current components + for (component, type_registration) in current_components { + updated_components.push((component.clone_value(), type_registration.clone())); + } + // then inject the new components: this also enables overwrite components set in the collection + for (component, type_registration) in reflect_components { + updated_components.push((component.clone_value(), type_registration)); + } + return (target_entity, updated_components) + //entity_components.insert(target_entity, updated_components); + } else { + return (target_entity, reflect_components); + // entity_components.insert(target_entity, reflect_components); + } +} + /// 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) { let mut extras = world.query_filtered::<(Entity, &Name, &GltfExtras, &Parent), (Added, Without)>(); + + let mut scene_extras = world.query_filtered::<(Entity, &Name, &GltfSceneExtras, &Parent), (Added, Without)>(); + let mut mesh_extras = world.query_filtered::<(Entity, &Name, &GltfMeshExtras, &Parent), (Added, Without)>(); + let mut material_extras = world.query_filtered::<(Entity, &Name, &GltfMaterialExtras, &Parent), (Added, Without)>(); + let mut entity_components: HashMap, TypeRegistration)>> = HashMap::new(); @@ -34,35 +72,54 @@ pub fn add_components_from_gltf_extras(world: &mut World) { let type_registry = type_registry.read(); let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); - // we assign the components specified /xxx_components objects to their parent node - let mut target_entity = entity; - // if the node contains "components" or ends with "_pa" (ie add to parent), the components will not be added to the entity itself but to its parent - // this is mostly used for Blender collections - if name.as_str().contains("components") || name.as_str().ends_with("_pa") { - debug!("adding components to parent"); - target_entity = parent.get(); - } - debug!("adding to {:?}", target_entity); - - // if there where already components set to be added to this entity (for example when entity_data was refering to a parent), update the vec of entity_components accordingly - // this allows for example blender collection to provide basic ecs data & the instances to override/ define their own values - if entity_components.contains_key(&target_entity) { - let mut updated_components: Vec<(Box, TypeRegistration)> = Vec::new(); - let current_components = &entity_components[&target_entity]; - // first inject the current components - for (component, type_registration) in current_components { - updated_components.push((component.clone_value(), type_registration.clone())); - } - // then inject the new components: this also enables overwrite components set in the collection - for (component, type_registration) in reflect_components { - updated_components.push((component.clone_value(), type_registration)); - } - entity_components.insert(target_entity, updated_components); - } else { - entity_components.insert(target_entity, reflect_components); - } + let (target_entity, updated_components) = find_entity_components(entity, name, parent, reflect_components, &entity_components); + entity_components.insert(target_entity, updated_components); } + + for (entity, name, extra, parent) in scene_extras.iter(world) { + debug!( + "Name: {}, entity {:?}, parent: {:?}, scene_extras {:?}", + name, entity, parent, extra + ); + + let type_registry: &AppTypeRegistry = world.resource(); + let type_registry = type_registry.read(); + let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); + + let (target_entity, updated_components) = find_entity_components(entity, name, parent, reflect_components, &entity_components); + entity_components.insert(target_entity, updated_components); + } + + for (entity, name, extra, parent) in mesh_extras.iter(world) { + debug!( + "Name: {}, entity {:?}, parent: {:?}, mesh_extras {:?}", + name, entity, parent, extra + ); + + let type_registry: &AppTypeRegistry = world.resource(); + let type_registry = type_registry.read(); + let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); + + let (target_entity, updated_components) = find_entity_components(entity, name, parent, reflect_components, &entity_components); + entity_components.insert(target_entity, updated_components); + } + + for (entity, name, extra, parent) in material_extras.iter(world) { + debug!( + "Name: {}, entity {:?}, parent: {:?}, material_extras {:?}", + name, entity, parent, extra + ); + + let type_registry: &AppTypeRegistry = world.resource(); + let type_registry = type_registry.read(); + let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); + + let (target_entity, updated_components) = find_entity_components(entity, name, parent, reflect_components, &entity_components); + entity_components.insert(target_entity, updated_components); + } + + for (entity, components) in entity_components { let type_registry: &AppTypeRegistry = world.resource(); let type_registry = type_registry.clone(); diff --git a/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs b/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs index fc0c741..5221431 100644 --- a/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs +++ b/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs @@ -1,5 +1,5 @@ use bevy::log::{debug, warn}; -use bevy::reflect::serde::UntypedReflectDeserializer; +use bevy::reflect::serde::ReflectDeserializer; use bevy::reflect::{Reflect, TypeRegistration, TypeRegistry}; use bevy::utils::HashMap; use ron::Value; @@ -68,7 +68,7 @@ fn components_string_to_components( 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 reflect_deserializer = UntypedReflectDeserializer::new(type_registry); + let reflect_deserializer = ReflectDeserializer::new(type_registry); let component = reflect_deserializer .deserialize(&mut deserializer) .unwrap_or_else(|_| { @@ -113,7 +113,7 @@ fn bevy_components_string_to_components( 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 reflect_deserializer = UntypedReflectDeserializer::new(type_registry); + let reflect_deserializer = ReflectDeserializer::new(type_registry); let component = reflect_deserializer .deserialize(&mut deserializer) .unwrap_or_else(|_| { diff --git a/crates/bevy_gltf_save_load/Cargo.toml b/crates/bevy_gltf_save_load/Cargo.toml index 4e7eeea..9d64b92 100644 --- a/crates/bevy_gltf_save_load/Cargo.toml +++ b/crates/bevy_gltf_save_load/Cargo.toml @@ -14,8 +14,8 @@ license = "MIT OR Apache-2.0" workspace = true [dependencies] -bevy = { version = "0.13", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } -bevy_gltf_blueprints = { version = "0.10", path = "../bevy_gltf_blueprints" } +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } +bevy_gltf_blueprints = { version = "0.11", path = "../bevy_gltf_blueprints" } [dev-dependencies] -bevy = { version = "0.13", default-features = false, features = ["dynamic_linking"] } +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } diff --git a/crates/bevy_gltf_save_load/src/saving.rs b/crates/bevy_gltf_save_load/src/saving.rs index b702ae8..47e4aa2 100644 --- a/crates/bevy_gltf_save_load/src/saving.rs +++ b/crates/bevy_gltf_save_load/src/saving.rs @@ -147,7 +147,7 @@ pub(crate) fn save_game(world: &mut World) { // dyn_scene.resources.append(&mut dyn_scene_root.resources); let serialized_scene = dyn_scene - .serialize_ron(world.resource::()) + .serialize(&world.resource::().read()) .unwrap(); let save_path = Path::new("assets") diff --git a/crates/bevy_registry_export/Cargo.toml b/crates/bevy_registry_export/Cargo.toml index 30e72cd..10df80f 100644 --- a/crates/bevy_registry_export/Cargo.toml +++ b/crates/bevy_registry_export/Cargo.toml @@ -11,11 +11,11 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -bevy = { version = "0.13", default-features = false, features = ["bevy_scene"] } -bevy_reflect = { version = "0.13", default-features = false } -bevy_app = { version = "0.13", default-features = false, features = ["bevy_reflect"] } -bevy_ecs = { version = "0.13", default-features = false, features = ["bevy_reflect"] } +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_scene"] } +bevy_reflect = { version = "0.14.0-rc.3", default-features = false } +bevy_app = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_reflect"] } +bevy_ecs = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_reflect"] } serde_json = "1.0.108" [dev-dependencies] -bevy = { version = "0.13", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/blenvy/Cargo.toml b/crates/blenvy/Cargo.toml new file mode 100644 index 0000000..926282e --- /dev/null +++ b/crates/blenvy/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "blenvy" +version = "0.0.1" +authors = ["Mark 'kaosat-dev' Moissette"] +description = "Allows you to define Bevy components direclty inside gltf files and instanciate the components on the Bevy side." +homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" +repository = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" +keywords = ["gamedev", "bevy", "assets", "gltf", "components"] +categories = ["game-development"] +edition = "2021" +license = "MIT OR Apache-2.0" + +[lints] +workspace = true + +[dependencies] +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } +serde = "1.0.188" +ron = "0.8.1" + +[dev-dependencies] +bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/blenvy/src/blender_settings.rs b/crates/blenvy/src/blender_settings.rs new file mode 100644 index 0000000..fe1b83c --- /dev/null +++ b/crates/blenvy/src/blender_settings.rs @@ -0,0 +1,8 @@ +use bevy::prelude::*; + +mod lighting; +pub use lighting::*; + +pub(crate) fn plugin(app: &mut App) { + app.add_plugins(lighting::plugin); +} diff --git a/crates/blenvy/src/blender_settings/lighting.rs b/crates/blenvy/src/blender_settings/lighting.rs new file mode 100644 index 0000000..622c0e1 --- /dev/null +++ b/crates/blenvy/src/blender_settings/lighting.rs @@ -0,0 +1,97 @@ +use bevy::pbr::DirectionalLightShadowMap; +use bevy::prelude::*; + +use crate::GltfComponentsSet; + +pub(crate) fn plugin(app: &mut App) { + app.register_type::() + .register_type::() + .register_type::() + .add_systems( + Update, + (process_lights, process_shadowmap, process_background_shader) + .after(GltfComponentsSet::Injection), + ); +} + +#[derive(Component, Reflect, Default, Debug, PartialEq, Clone)] +#[reflect(Component)] +#[non_exhaustive] +/// The properties of a light's shadow , to enable controlling per light shadows from Blender +pub struct BlenderLightShadows { + pub enabled: bool, + pub buffer_bias: f32, +} + +/// The background color as described by Blender's [background shader](https://docs.blender.org/manual/en/latest/render/shader_nodes/shader/background.html). +#[derive(Component, Reflect, Default, Debug, PartialEq, Clone)] +#[reflect(Component)] +#[non_exhaustive] +pub struct BlenderBackgroundShader { + pub color: Color, + pub strength: f32, +} + +/// The settings used by EEVEE's [shadow rendering](https://docs.blender.org/manual/en/latest/render/eevee/render_settings/shadows.html). +#[derive(Component, Reflect, Default, Debug, PartialEq, Clone)] +#[reflect(Component)] +#[non_exhaustive] +pub struct BlenderShadowSettings { + pub cascade_size: usize, +} + +fn process_lights( + mut directional_lights: Query< + (&mut DirectionalLight, Option<&BlenderLightShadows>), + Added, + >, + mut spot_lights: Query<(&mut SpotLight, Option<&BlenderLightShadows>), Added>, + mut point_lights: Query<(&mut PointLight, Option<&BlenderLightShadows>), Added>, +) { + for (mut light, blender_light_shadows) in directional_lights.iter_mut() { + if let Some(blender_light_shadows) = blender_light_shadows { + light.shadows_enabled = blender_light_shadows.enabled; + } else { + light.shadows_enabled = true; + } + } + for (mut light, blender_light_shadows) in spot_lights.iter_mut() { + if let Some(blender_light_shadows) = blender_light_shadows { + light.shadows_enabled = blender_light_shadows.enabled; + } else { + light.shadows_enabled = true; + } + } + + for (mut light, blender_light_shadows) in point_lights.iter_mut() { + if let Some(blender_light_shadows) = blender_light_shadows { + light.shadows_enabled = blender_light_shadows.enabled; + } else { + light.shadows_enabled = true; + } + } +} + +fn process_shadowmap( + shadowmaps: Query<&BlenderShadowSettings, Added>, + mut commands: Commands, +) { + for shadowmap in shadowmaps.iter() { + commands.insert_resource(DirectionalLightShadowMap { + size: shadowmap.cascade_size, + }); + } +} + +fn process_background_shader( + background_shaders: Query<&BlenderBackgroundShader, Added>, + mut commands: Commands, +) { + for background_shader in background_shaders.iter() { + commands.insert_resource(AmbientLight { + color: background_shader.color, + // Just a guess, see + brightness: background_shader.strength * 400.0, + }); + } +} diff --git a/crates/blenvy/src/lib.rs b/crates/blenvy/src/lib.rs new file mode 100644 index 0000000..79af3d7 --- /dev/null +++ b/crates/blenvy/src/lib.rs @@ -0,0 +1,78 @@ +pub mod utils; +pub use utils::*; + +pub mod ronstring_to_reflect_component; +pub use ronstring_to_reflect_component::*; + +pub mod process_gltfs; +pub use process_gltfs::*; + +pub mod blender_settings; + +use bevy::{ + ecs::{component::Component, reflect::ReflectComponent, system::Resource}, + 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 +/// It will automatically run every time you load a gltf file +/// Add this plugin to your Bevy app to get access to this feature +/// ``` +/// # use bevy::prelude::*; +/// # use bevy::gltf::*; +/// # use bevy_gltf_components::ComponentsFromGltfPlugin; +/// +/// //too barebones of an example to be meaningfull, please see https://github.com/kaosat-dev/Blender_bevy_components_workflow/examples/basic for a real example +/// fn main() { +/// App::new() +/// .add_plugins(DefaultPlugins) +/// .add_plugin(ComponentsFromGltfPlugin) +/// .add_system(spawn_level) +/// .run(); +/// } +/// +/// fn spawn_level( +/// asset_server: Res, +/// mut commands: bevy::prelude::Commands, +/// keycode: Res>, + +/// ){ +/// if keycode.just_pressed(KeyCode::Return) { +/// commands.spawn(SceneBundle { +/// scene: asset_server.load("basic/models/level1.glb"), +/// transform: Transform::from_xyz(2.0, 0.0, -5.0), +/// ..Default::default() +/// }); +/// } +///} +/// ``` + +/// 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)] +/// systemset to order your systems after the component injection when needed +pub enum GltfComponentsSet { + Injection, +} + +#[derive(Clone, Resource)] +pub struct GltfComponentsConfig {} + +#[derive(Default)] +pub struct ComponentsFromGltfPlugin {} + +impl Plugin for ComponentsFromGltfPlugin { + fn build(&self, app: &mut App) { + app.add_plugins(blender_settings::plugin) + .register_type::() + .insert_resource(GltfComponentsConfig {}) + .add_systems( + Update, + (add_components_from_gltf_extras).in_set(GltfComponentsSet::Injection), + ); + } +} diff --git a/crates/blenvy/src/process_gltfs.rs b/crates/blenvy/src/process_gltfs.rs new file mode 100644 index 0000000..1afb3d3 --- /dev/null +++ b/crates/blenvy/src/process_gltfs.rs @@ -0,0 +1,130 @@ +use bevy::{ + core::Name, + ecs::{ + entity::Entity, + query::{Added, Without}, + reflect::{AppTypeRegistry, ReflectComponent}, + world::World, + }, + gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras}, + hierarchy::Parent, + log::debug, + reflect::{Reflect, TypeRegistration}, + utils::HashMap, +}; + +use crate::{ronstring_to_reflect_component, GltfProcessed}; + +fn bla_balb(entity: Entity, name: &Name, parent: &Parent, reflect_components: Vec<(Box, TypeRegistration)>, mut entity_components: HashMap, TypeRegistration)>>){ + // we assign the components specified /xxx_components objects to their parent node + let mut target_entity = entity; + // if the node contains "components" or ends with "_pa" (ie add to parent), the components will not be added to the entity itself but to its parent + // this is mostly used for Blender collections + if name.as_str().contains("components") || name.as_str().ends_with("_pa") { + debug!("adding components to parent"); + target_entity = parent.get(); + } + debug!("adding to {:?}", target_entity); + + // if there where already components set to be added to this entity (for example when entity_data was refering to a parent), update the vec of entity_components accordingly + // this allows for example blender collection to provide basic ecs data & the instances to override/ define their own values + if entity_components.contains_key(&target_entity) { + let mut updated_components: Vec<(Box, TypeRegistration)> = Vec::new(); + let current_components = &entity_components[&target_entity]; + // first inject the current components + for (component, type_registration) in current_components { + updated_components.push((component.clone_value(), type_registration.clone())); + } + // then inject the new components: this also enables overwrite components set in the collection + for (component, type_registration) in reflect_components { + updated_components.push((component.clone_value(), type_registration)); + } + entity_components.insert(target_entity, updated_components); + } else { + entity_components.insert(target_entity, reflect_components); + } +} + +/// 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) { + let mut extras = + world.query_filtered::<(Entity, &Name, &GltfExtras, &Parent), (Added, Without)>(); + + let mut scene_extras = world.query_filtered::<(Entity, &Name, &GltfSceneExtras, &Parent), (Added, Without)>(); + let mut mesh_extras = world.query_filtered::<(Entity, &Name, &GltfMeshExtras, &Parent), (Added, Without)>(); + let mut material_extras = world.query_filtered::<(Entity, &Name, &GltfMaterialExtras, &Parent), (Added, Without)>(); + + let mut entity_components: HashMap, TypeRegistration)>> = + HashMap::new(); + + // let gltf_components_config = world.resource::(); + + for (entity, name, extra, parent) in extras.iter(world) { + debug!( + "Name: {}, entity {:?}, parent: {:?}, extras {:?}", + name, entity, parent, extra + ); + + let type_registry: &AppTypeRegistry = world.resource(); + let type_registry = type_registry.read(); + let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); + + bla_balb(entity, name, parent, reflect_components, entity_components); + + /* + // we assign the components specified /xxx_components objects to their parent node + let mut target_entity = entity; + // if the node contains "components" or ends with "_pa" (ie add to parent), the components will not be added to the entity itself but to its parent + // this is mostly used for Blender collections + if name.as_str().contains("components") || name.as_str().ends_with("_pa") { + debug!("adding components to parent"); + target_entity = parent.get(); + } + debug!("adding to {:?}", target_entity); + + // if there where already components set to be added to this entity (for example when entity_data was refering to a parent), update the vec of entity_components accordingly + // this allows for example blender collection to provide basic ecs data & the instances to override/ define their own values + if entity_components.contains_key(&target_entity) { + let mut updated_components: Vec<(Box, TypeRegistration)> = Vec::new(); + let current_components = &entity_components[&target_entity]; + // first inject the current components + for (component, type_registration) in current_components { + updated_components.push((component.clone_value(), type_registration.clone())); + } + // then inject the new components: this also enables overwrite components set in the collection + for (component, type_registration) in reflect_components { + updated_components.push((component.clone_value(), type_registration)); + } + entity_components.insert(target_entity, updated_components); + } else { + entity_components.insert(target_entity, reflect_components); + } */ + } + + for (entity, components) in entity_components { + let type_registry: &AppTypeRegistry = world.resource(); + let type_registry = type_registry.clone(); + let type_registry = type_registry.read(); + + if !components.is_empty() { + debug!("--entity {:?}, components {}", entity, components.len()); + } + for (component, type_registration) in components { + debug!( + "------adding {} {:?}", + component.get_represented_type_info().unwrap().type_path(), + component + ); + + { + let mut entity_mut = world.entity_mut(entity); + type_registration + .data::() + .expect("Unable to reflect component") + .insert(&mut entity_mut, &*component, &type_registry); + + entity_mut.insert(GltfProcessed); // this is how can we insert any additional components + } + } + } +} diff --git a/crates/blenvy/src/ronstring_to_reflect_component.rs b/crates/blenvy/src/ronstring_to_reflect_component.rs new file mode 100644 index 0000000..5221431 --- /dev/null +++ b/crates/blenvy/src/ronstring_to_reflect_component.rs @@ -0,0 +1,134 @@ +use bevy::log::{debug, warn}; +use bevy::reflect::serde::ReflectDeserializer; +use bevy::reflect::{Reflect, TypeRegistration, TypeRegistry}; +use bevy::utils::HashMap; +use ron::Value; +use serde::de::DeserializeSeed; + +use super::capitalize_first_letter; + +pub fn ronstring_to_reflect_component( + ron_string: &str, + type_registry: &TypeRegistry, +) -> Vec<(Box, TypeRegistration)> { + let lookup: HashMap = ron::from_str(ron_string).unwrap(); + let mut components: Vec<(Box, TypeRegistration)> = Vec::new(); + // println!("ron_string {:?}", ron_string); + for (name, value) in lookup.into_iter() { + let parsed_value: String = match value.clone() { + Value::String(str) => { + str + } + _ => ron::to_string(&value).unwrap().to_string(), + }; + + if name.as_str() == "bevy_components" { + bevy_components_string_to_components(parsed_value, type_registry, &mut components); + } else { + components_string_to_components( + name, + value, + parsed_value, + type_registry, + &mut components, + ); + } + } + components +} + +fn components_string_to_components( + name: String, + value: Value, + parsed_value: String, + type_registry: &TypeRegistry, + components: &mut Vec<(Box, TypeRegistration)>, +) { + let type_string = name.replace("component: ", "").trim().to_string(); + let capitalized_type_name = capitalize_first_letter(type_string.as_str()); + + if let Some(type_registration) = + type_registry.get_with_short_type_path(capitalized_type_name.as_str()) + { + debug!("TYPE INFO {:?}", type_registration.type_info()); + + let ron_string = format!( + "{{ \"{}\":{} }}", + type_registration.type_info().type_path(), + parsed_value + ); + + // usefull to determine what an entity looks like Serialized + /*let test_struct = CameraRenderGraph::new("name"); + let serializer = ReflectSerializer::new(&test_struct, &type_registry); + let serialized = + ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap(); + println!("serialized Component {}", serialized);*/ + + 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 reflect_deserializer = ReflectDeserializer::new(type_registry); + let component = reflect_deserializer + .deserialize(&mut deserializer) + .unwrap_or_else(|_| { + panic!( + "failed to deserialize component {} with value: {:?}", + name, value + ) + }); + + debug!("component {:?}", component); + debug!("real type {:?}", component.get_represented_type_info()); + components.push((component, type_registration.clone())); + debug!("found type registration for {}", capitalized_type_name); + } else { + warn!("no type registration for {}", capitalized_type_name); + } +} + +fn bevy_components_string_to_components( + parsed_value: String, + type_registry: &TypeRegistry, + components: &mut Vec<(Box, TypeRegistration)>, +) { + let lookup: HashMap = ron::from_str(&parsed_value).unwrap(); + for (key, value) in lookup.into_iter() { + let parsed_value: String = match value.clone() { + Value::String(str) => { + str + } + _ => ron::to_string(&value).unwrap().to_string(), + }; + + if let Some(type_registration) = type_registry.get_with_type_path(key.as_str()) { + debug!("TYPE INFO {:?}", type_registration.type_info()); + + let ron_string = format!( + "{{ \"{}\":{} }}", + type_registration.type_info().type_path(), + parsed_value + ); + + 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 reflect_deserializer = ReflectDeserializer::new(type_registry); + let component = reflect_deserializer + .deserialize(&mut deserializer) + .unwrap_or_else(|_| { + panic!( + "failed to deserialize component {} with value: {:?}", + key, value + ) + }); + + debug!("component {:?}", component); + debug!("real type {:?}", component.get_represented_type_info()); + components.push((component, type_registration.clone())); + debug!("found type registration for {}", key); + } else { + warn!("no type registration for {}", key); + } + } +} diff --git a/crates/blenvy/src/utils.rs b/crates/blenvy/src/utils.rs new file mode 100644 index 0000000..14d6da3 --- /dev/null +++ b/crates/blenvy/src/utils.rs @@ -0,0 +1,3 @@ +pub fn capitalize_first_letter(s: &str) -> String { + s[0..1].to_uppercase() + &s[1..] +} diff --git a/testing/bevy_example/Cargo.toml b/testing/bevy_example/Cargo.toml index 4b8a556..f3dad90 100644 --- a/testing/bevy_example/Cargo.toml +++ b/testing/bevy_example/Cargo.toml @@ -5,14 +5,14 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -bevy = { version = "0.13", features = ["dynamic_linking"] } +bevy = { version = "0.14.0-rc.3", features = ["dynamic_linking"] } bevy_gltf_blueprints = { path = "../../crates/bevy_gltf_blueprints" } bevy_registry_export = { path = "../../crates/bevy_registry_export" } # bevy_gltf_worlflow_examples_common_rapier = { path = "../../examples/common_rapier" } -bevy_gltf_worlflow_examples_common = { path = "../../examples/common" } +#bevy_gltf_worlflow_examples_common = { path = "../../examples/common" } #evy_rapier3d = { version = "0.25.0", features = ["serde-serialize", "debug-render-3d", "enhanced-determinism"] } -bevy_asset_loader = { version = "0.20", features = ["standard_dynamic_assets"] } -bevy_editor_pls = { version = "0.8" } +#bevy_asset_loader = { version = "0.20", features = ["standard_dynamic_assets"] } +#bevy_editor_pls = { version = "0.8" } rand = "0.8.5" json-writer ="0.3" \ No newline at end of file diff --git a/testing/bevy_example/src/game/animation.rs b/testing/bevy_example/src/game/animation.rs index 821fa94..8dd2783 100644 --- a/testing/bevy_example/src/game/animation.rs +++ b/testing/bevy_example/src/game/animation.rs @@ -34,6 +34,7 @@ pub fn setup_main_scene_animations(asset_server: Res, mut commands: commands.insert_resource(AnimTest(asset_server.load("levels/World.glb"))); } +/* #[allow(clippy::type_complexity)] pub fn animations( added_animation_players: Query<(Entity, &Name, &AnimationPlayer)>, @@ -225,7 +226,7 @@ pub fn play_animations( } } } - +*/ pub fn react_to_animation_markers( mut animation_marker_events: EventReader, ) { diff --git a/testing/bevy_example/src/game/in_game.rs b/testing/bevy_example/src/game/in_game.rs index e3176c4..5afec9e 100644 --- a/testing/bevy_example/src/game/in_game.rs +++ b/testing/bevy_example/src/game/in_game.rs @@ -1,6 +1,6 @@ use bevy::prelude::*; use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, BlueprintPath, GameWorldTag}; -use bevy_gltf_worlflow_examples_common::{GameState, InAppRunning}; +use crate::{GameState, InAppRunning}; //use bevy_rapier3d::prelude::Velocity; use rand::Rng; diff --git a/testing/bevy_example/src/game/mod.rs b/testing/bevy_example/src/game/mod.rs index 37e065c..3c47dc6 100644 --- a/testing/bevy_example/src/game/mod.rs +++ b/testing/bevy_example/src/game/mod.rs @@ -1,8 +1,9 @@ -pub mod animation; pub mod in_game; -pub use animation::*; pub use in_game::*; +pub mod animation; +pub use animation::*; + use std::{collections::HashMap, fs, time::Duration}; use bevy_gltf_blueprints::{ @@ -13,12 +14,14 @@ use bevy::{ prelude::*, render::view::screenshot::ScreenshotManager, time::common_conditions::on_timer, window::PrimaryWindow, }; -use bevy_gltf_worlflow_examples_common::{AppState, GameState}; +use crate::{AppState, GameState}; use json_writer::to_json_string; fn start_game(mut next_app_state: ResMut>) { - next_app_state.set(AppState::AppLoading); + println!("START GAME"); + //next_app_state.set(AppState::AppLoading); + next_app_state.set(AppState::AppRunning); } // if the export from Blender worked correctly, we should have animations (simplified here by using AnimationPlayerLink) @@ -121,7 +124,7 @@ fn generate_screenshot( } fn exit_game(mut app_exit_events: ResMut>) { - app_exit_events.send(bevy::app::AppExit); + app_exit_events.send(bevy::app::AppExit::Success); } pub struct GamePlugin; @@ -134,16 +137,18 @@ impl Plugin for GamePlugin { .add_systems(Update, (spawn_test).run_if(in_state(GameState::InGame))) .add_systems(Update, validate_export) + //.add_systems(OnEnter(AppState::CoreLoading), start_game) + .add_systems(OnEnter(AppState::MenuRunning), start_game) .add_systems(OnEnter(AppState::AppRunning), setup_game) .add_systems(OnEnter(AppState::MenuRunning), setup_main_scene_animations) - .add_systems(Update, (animations) + /* .add_systems(Update, (animations) .run_if(in_state(AppState::AppRunning)) .after(GltfBlueprintsSet::AfterSpawn) ) .add_systems(Update, play_animations) - .add_systems(Update, react_to_animation_markers) + .add_systems(Update, react_to_animation_markers)*/ /*.add_systems(Update, generate_screenshot.run_if(on_timer(Duration::from_secs_f32(0.2)))) // TODO: run once .add_systems( diff --git a/testing/bevy_example/src/hierarchy_debug.rs b/testing/bevy_example/src/hierarchy_debug.rs new file mode 100644 index 0000000..6834f48 --- /dev/null +++ b/testing/bevy_example/src/hierarchy_debug.rs @@ -0,0 +1,146 @@ +use bevy::{gltf::{GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras}, prelude::*}; +use bevy_gltf_blueprints::{AllAssets, BlueprintInstanceReady}; + +use crate::BasicTest; + +#[derive(Component)] +pub struct HiearchyDebugTag; + +pub fn setup_hierarchy_debug(mut commands: Commands, asset_server: Res){ + // a place to display the extras on screen + commands.spawn(( + TextBundle::from_section( + "", + TextStyle { + color: LinearRgba { red: 1.0, green:0.0, blue: 0.0, alpha: 1.0}.into(), + font_size: 10., + ..default() + }, + ) + .with_style(Style { + position_type: PositionType::Absolute, + top: Val::Px(12.0), + left: Val::Px(12.0), + ..default() + }), + HiearchyDebugTag, + )); +} + + +pub fn get_descendants( + all_children: &Query<&Children>, + all_names:&Query<&Name>, root: &Entity, + nesting: usize, + to_check: &Query<&BasicTest>//&Query<(&BlueprintInstanceReady, &AllAssets)>, +) + -> String +{ + + let mut hierarchy_display: Vec = vec![]; + let root_name = all_names.get(*root); + let name; + if root_name.is_ok() { + name = root_name.unwrap().to_string(); + }else { + name = "no_name".to_string() + } + + let components_to_check = to_check.get(*root); + + hierarchy_display.push( format!("{}{} ({:?})", " ".repeat(nesting), name, 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); + hierarchy_display.push(child_descendants_display); + } + } + return hierarchy_display.join("\n"); +} + +pub fn draw_hierarchy_debug( + root: Query<(Entity, Option<&Name>, &Children), (Without)>, + all_children: Query<&Children>, + all_names:Query<&Name>, + + to_check: Query<&BasicTest>,//Query<(&BlueprintInstanceReady, &AllAssets)>, + mut display: Query<&mut Text, With>, +){ + let mut hierarchy_display: Vec = vec![]; + + 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)); + // let mut children = all_children.get(root_entity); + /*for child in children.iter() { + // hierarchy_display + let name = all_names.get(*child); //.unwrap_or(&Name::new("no name")); + hierarchy_display.push(format!(" {:?}", name)) + }*/ + + // + } + let mut display = display.single_mut(); + display.sections[0].value = hierarchy_display.join("\n"); +} + + + +////////:just some testing for gltf extras +fn check_for_gltf_extras( +gltf_extras_per_entity: Query<( + Entity, + Option<&Name>, + Option<&GltfSceneExtras>, + Option<&GltfExtras>, + Option<&GltfMeshExtras>, + Option<&GltfMaterialExtras>, +)>, +mut display: Query<&mut Text, With>, +) { +let mut gltf_extra_infos_lines: Vec = vec![]; + +for (id, name, scene_extras, extras, mesh_extras, material_extras) in + gltf_extras_per_entity.iter() +{ + if scene_extras.is_some() + //|| extras.is_some() + || mesh_extras.is_some() + || material_extras.is_some() + { + let formatted_extras = format!( + "Extras per entity {} ('Name: {}'): +- scene extras: {:?} +- mesh extras: {:?} +- material extras: {:?} + ", + id, + name.unwrap_or(&Name::default()), + scene_extras, + //extras, + mesh_extras, + material_extras + ); + gltf_extra_infos_lines.push(formatted_extras); + } + let mut display = display.single_mut(); + display.sections[0].value = gltf_extra_infos_lines.join("\n"); +} +} + +pub struct HiearchyDebugPlugin; +impl Plugin for HiearchyDebugPlugin { + fn build(&self, app: &mut App) { + app + .add_systems(Startup, setup_hierarchy_debug) + .add_systems(Update, draw_hierarchy_debug) + //.add_systems(Update, check_for_gltf_extras) + + ; + } +} diff --git a/testing/bevy_example/src/main.rs b/testing/bevy_example/src/main.rs index cdee4ac..60f3a22 100644 --- a/testing/bevy_example/src/main.rs +++ b/testing/bevy_example/src/main.rs @@ -1,5 +1,7 @@ use bevy::prelude::*; -use bevy_gltf_worlflow_examples_common::CommonPlugin; +// use bevy_gltf_worlflow_examples_common::CommonPlugin; +mod state; +use state::*; mod core; use crate::core::*; @@ -11,12 +13,18 @@ mod dupe_components; mod test_components; use test_components::*; +mod hierarchy_debug; +use hierarchy_debug::*; + fn main() { App::new() .add_plugins(( DefaultPlugins.set(AssetPlugin::default()), + + HiearchyDebugPlugin, // our custom plugins - CommonPlugin, + // CommonPlugin, + StatePlugin, CorePlugin, // reusable plugins GamePlugin, // specific to our game ComponentsTestPlugin, // Showcases different type of components /structs diff --git a/testing/bevy_example/src/state.rs b/testing/bevy_example/src/state.rs new file mode 100644 index 0000000..ec092e1 --- /dev/null +++ b/testing/bevy_example/src/state.rs @@ -0,0 +1,59 @@ +use bevy::prelude::*; + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default, States)] +pub enum AppState { + CoreLoading, + #[default] + MenuRunning, + AppLoading, + AppRunning, + AppEnding, +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Default, States)] +pub enum GameState { + #[default] + None, + + InMenu, + InGame, + + InGameOver, + + InSaving, + InLoading, +} + +// tag components for all entities within a certain state (for despawning them if needed) , FIXME: seems kinda hack-ish +#[derive(Component)] +pub struct InCoreLoading; +#[derive(Component, Default)] +pub struct InMenuRunning; +#[derive(Component)] + +pub struct InAppRunning; + +// components for tagging in game vs in game menu stuff +#[derive(Component, Default)] +pub struct InMainMenu; + +#[derive(Component, Default)] +pub struct InMenu; + +#[derive(Component, Default)] +pub struct InGame; + +#[derive(Component, Default)] +pub struct InGameSaving; + +#[derive(Component, Default)] +pub struct InGameLoading; + +pub struct StatePlugin; +impl Plugin for StatePlugin { + fn build(&self, app: &mut App) { + app + .init_state::() + .init_state::(); + } +}