From 6cbb144746ae73dcdd1c39733aeeecb154520151 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Sat, 29 Jun 2024 01:51:49 +0200 Subject: [PATCH] feat(Blenvy:Bevy): * cleaned up hot reload code a bit * renamed a few things for clarity * experimented with hiding entity while spawning & showing it again after spawn to try and remove "flashes" happening when spawning blueprints with lights * for testing example, fixed dynamic spawner test --- crates/blenvy/src/blueprints/assets.rs | 4 +- crates/blenvy/src/blueprints/materials.rs | 6 +- .../src/blueprints/spawn_from_blueprints.rs | 118 ++++-------------- .../src/blueprints/spawn_post_process.rs | 5 +- testing/bevy_example/src/game/in_game.rs | 2 +- tools/blenvy/TODO.md | 11 +- 6 files changed, 46 insertions(+), 100 deletions(-) diff --git a/crates/blenvy/src/blueprints/assets.rs b/crates/blenvy/src/blueprints/assets.rs index 4aab574..4bd0e26 100644 --- a/crates/blenvy/src/blueprints/assets.rs +++ b/crates/blenvy/src/blueprints/assets.rs @@ -58,12 +58,12 @@ pub(crate) struct AssetLoadTracker { /// helper component, for tracking loaded assets #[derive(Component, Debug)] -pub(crate) struct BlenvyAssetsLoadState { +pub(crate) struct BlueprintAssetsLoadState { pub all_loaded: bool, pub asset_infos: Vec, pub progress: f32, } -impl Default for BlenvyAssetsLoadState { +impl Default for BlueprintAssetsLoadState { fn default() -> Self { Self { all_loaded: Default::default(), diff --git a/crates/blenvy/src/blueprints/materials.rs b/crates/blenvy/src/blueprints/materials.rs index 3f77bbb..8aa652d 100644 --- a/crates/blenvy/src/blueprints/materials.rs +++ b/crates/blenvy/src/blueprints/materials.rs @@ -17,7 +17,7 @@ use bevy::{ render::mesh::Mesh, }; -use crate::{AssetLoadTracker, BlenvyAssetsLoadState, BlenvyConfig, BlueprintInstanceReady}; +use crate::{AssetLoadTracker, BlueprintAssetsLoadState, BlenvyConfig, BlueprintInstanceReady}; #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] @@ -72,7 +72,7 @@ pub(crate) fn materials_inject( commands .entity(entity) - .insert(BlenvyAssetsLoadState { + .insert(BlueprintAssetsLoadState { all_loaded: false, asset_infos, ..Default::default() @@ -86,7 +86,7 @@ pub(crate) fn materials_inject( // TODO, merge with blueprints_check_assets_loading, make generic ? pub(crate) fn check_for_material_loaded( mut blueprint_assets_to_load: Query< - (Entity, &mut BlenvyAssetsLoadState), + (Entity, &mut BlueprintAssetsLoadState), With, >, asset_server: Res, diff --git a/crates/blenvy/src/blueprints/spawn_from_blueprints.rs b/crates/blenvy/src/blueprints/spawn_from_blueprints.rs index 2ae0d52..96d5984 100644 --- a/crates/blenvy/src/blueprints/spawn_from_blueprints.rs +++ b/crates/blenvy/src/blueprints/spawn_from_blueprints.rs @@ -1,9 +1,9 @@ use std::path::{Path, PathBuf}; -use bevy::{asset::LoadedUntypedAsset, gltf::Gltf, prelude::*, scene::SceneInstance, transform::commands, utils::hashbrown::HashMap}; +use bevy::{asset::LoadedUntypedAsset, gltf::Gltf, prelude::*, render::view::visibility, scene::SceneInstance, transform::commands, utils::hashbrown::HashMap}; use serde_json::Value; -use crate::{BlueprintAssets, BlenvyAssetsLoadState, AssetLoadTracker, BlenvyConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded}; +use crate::{BlueprintAssets, BlueprintAssetsLoadState, AssetLoadTracker, BlenvyConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded}; /// this is a flag component for our levels/game world #[derive(Component)] @@ -164,12 +164,13 @@ asset_server: Res, if !asset_infos.is_empty() { commands .entity(entity) - .insert(BlenvyAssetsLoadState { + .insert(BlueprintAssetsLoadState { all_loaded: false, asset_infos, ..Default::default() }) - .insert(BlueprintAssetsNotLoaded); + .insert(BlueprintAssetsNotLoaded) + ; } else { commands.entity(entity).insert(BlueprintAssetsLoaded); } @@ -178,7 +179,7 @@ asset_server: Res, pub(crate) fn blueprints_check_assets_loading( mut blueprint_assets_to_load: Query< - (Entity, Option<&Name>, &BlueprintInfo, &mut BlenvyAssetsLoadState), + (Entity, Option<&Name>, &BlueprintInfo, &mut BlueprintAssetsLoadState), With, >, asset_server: Res, @@ -222,7 +223,7 @@ pub(crate) fn blueprints_check_assets_loading( .entity(entity) .insert(BlueprintAssetsLoaded) .remove::() - //.remove::() //REMOVE it in release mode/ when hot reload is off, keep it for dev/hot reload + //.remove::() //REMOVE it in release mode/ when hot reload is off, keep it for dev/hot reload ; }else { println!("LOADING: done for ALL assets of {:?} (instance of {}): {} ",entity_name, blueprint_info.path, progress * 100.0); @@ -233,7 +234,7 @@ pub(crate) fn blueprints_check_assets_loading( /* pub(crate) fn hot_reload_asset_check( mut blueprint_assets: Query< - (Entity, Option<&Name>, &BlueprintInfo, &mut BlenvyAssetsLoadState)>, + (Entity, Option<&Name>, &BlueprintInfo, &mut BlueprintAssetsLoadState)>, asset_server: Res, mut commands: Commands, ){ @@ -260,109 +261,42 @@ use bevy::asset::AssetEvent; pub(crate) fn react_to_asset_changes( mut gltf_events: EventReader>, mut untyped_events: EventReader>, - mut blueprint_assets: Query<(Entity, Option<&Name>, &BlueprintInfo, &mut BlenvyAssetsLoadState, Option<&Children>)>, + mut blueprint_assets: Query<(Entity, Option<&Name>, &BlueprintInfo, &mut BlueprintAssetsLoadState, Option<&Children>)>, asset_server: Res, mut commands: Commands, ) { - for event in untyped_events.read() { - for (entity, entity_name, blueprint_info, mut assets_to_load, c) in blueprint_assets.iter_mut() { - for tracker in assets_to_load.asset_infos.iter_mut() { - let asset_id = tracker.id; - - println!("changed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_modified(asset_id)); - } - } - - match event { - AssetEvent::Added { id } => { - // React to the image being created - println!("Added untyped {:?}", asset_server.get_path(*id)) - } - AssetEvent::LoadedWithDependencies { id } => { - // React to the image being loaded - // after all dependencies - println!("Loaded with deps untyped {:?}", asset_server.get_path(*id)) - } - AssetEvent::Modified { id } => { - // React to the image being modified - println!("Modified untyped {:?}", asset_server.get_path(*id)) - } - AssetEvent::Removed { id } => { - // React to the image being removed - println!("Removed untyped {:?}", asset_server.get_path(*id)) - }, - AssetEvent::Unused { id } => { - // React to the last strong handle for the asset being dropped - println!("unused untyped {:?}", asset_server.get_path(*id)) - } - } - } for event in gltf_events.read() { // LoadedUntypedAsset - - /*for (entity, entity_name, blueprint_info, mut assets_to_load) in blueprint_assets.iter_mut() { - for tracker in assets_to_load.asset_infos.iter_mut() { - let asset_id = tracker.id; - if blueprint_info.path.ends_with("glb") || blueprint_info.path.ends_with("gltf") { - // let typed_asset_id = asset_server.get_handle(blueprint_info.path); - let foo: Handle = asset_server.load(blueprint_info.path.clone()); - //println!("changed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_modified(foo.id())); - println!("changed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_modified(foo.id())); - println!("added {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_added(foo.id())); - println!("removed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_removed(foo.id())); - println!("loaded with deps {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_loaded_with_dependencies(foo.id())); - - } - } - }*/ - match event { - AssetEvent::Added { id } => { - // React to the image being created - println!("Added gltf, path {:?}", asset_server.get_path(*id)); - - } - AssetEvent::LoadedWithDependencies { id } => { - // React to the image being loaded - // after all dependencies - println!("Loaded gltf with deps{:?}", asset_server.get_path(*id)) - } AssetEvent::Modified { id } => { // React to the image being modified - println!("Modified gltf {:?}", asset_server.get_path(*id)); - + // println!("Modified gltf {:?}", asset_server.get_path(*id)); for (entity, entity_name, blueprint_info, mut assets_to_load, children) in blueprint_assets.iter_mut() { for tracker in assets_to_load.asset_infos.iter_mut() { - if tracker.path == asset_server.get_path(*id).unwrap().to_string() { - println!("HOLY MOLY IT DETECTS !!, now respawn {:?}", entity_name); - if children.is_some() { - for child in children.unwrap().iter(){ - commands.entity(*child).despawn_recursive(); - + if asset_server.get_path(*id).is_some() { + if tracker.path == asset_server.get_path(*id).unwrap().to_string() { + println!("HOLY MOLY IT DETECTS !!, now respawn {:?}", entity_name); + if children.is_some() { + for child in children.unwrap().iter(){ + commands.entity(*child).despawn_recursive(); + } } - } - commands.entity(entity) - .remove::() - .remove::() - .remove::() - .insert(SpawnHere); + commands.entity(entity) + .remove::() + .remove::() + .remove::() + .insert(SpawnHere); - break; + break; + } } } } } - AssetEvent::Removed { id } => { - // React to the image being removed - println!("Removed gltf {:?}", asset_server.get_path(*id)) - }, - AssetEvent::Unused { id } => { - // React to the last strong handle for the asset being dropped - println!("unused gltf {:?}", asset_server.get_path(*id)) - } + _ => {} } } } @@ -447,6 +381,8 @@ pub(crate) fn blueprints_spawn( SceneBundle { scene: scene.clone(), transform: transforms, + visibility: Visibility::Hidden, + ..Default::default() }, Spawned, diff --git a/crates/blenvy/src/blueprints/spawn_post_process.rs b/crates/blenvy/src/blueprints/spawn_post_process.rs index 62a2e1d..6effb6a 100644 --- a/crates/blenvy/src/blueprints/spawn_post_process.rs +++ b/crates/blenvy/src/blueprints/spawn_post_process.rs @@ -99,10 +99,11 @@ pub(crate) fn spawned_blueprint_post_process( 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::(); // 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(); - + commands.entity(original).insert( Visibility::Visible + ); blueprint_events.send(BlueprintEvent::Spawned {blueprint_name: blueprint_info.name.clone(), blueprint_path: blueprint_info.path.clone() }); debug!("DONE WITH POST PROCESS"); diff --git a/testing/bevy_example/src/game/in_game.rs b/testing/bevy_example/src/game/in_game.rs index 9ecc56a..d4e0593 100644 --- a/testing/bevy_example/src/game/in_game.rs +++ b/testing/bevy_example/src/game/in_game.rs @@ -62,7 +62,7 @@ pub fn spawn_test( let new_entity = commands .spawn(( BluePrintBundle { - blueprint: BlueprintInfo{name: "Health_Pickup".into() , path:"foo/bar.glb".into()}, // FIXME + blueprint: BlueprintInfo{name: "Blueprint1".into() , path:"blueprints/Blueprint1.glb".into()}, // FIXME ..Default::default() }, bevy::prelude::Name::from(format!("test{}", name_index)), diff --git a/tools/blenvy/TODO.md b/tools/blenvy/TODO.md index be5d2e6..f6845bf 100644 --- a/tools/blenvy/TODO.md +++ b/tools/blenvy/TODO.md @@ -210,6 +210,7 @@ Blender side: - [ ] for scenes, scan for used materials of all non instance objects (TODO: what about overrides ?) - [ ] add a way of visualizing per blueprint instances ? +- [ ] display export path of blueprints (mostly external) ? Bevy Side: - [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead @@ -220,7 +221,15 @@ Bevy Side: - [ ] remove/replace bevy editor pls with some native ui to display hierarchies - [ ] a full fledged demo (including physics & co) - [ ] other examples without interactions or physics -- [x] try out hot reloading +- [ ] add hot reloading + - [x] basics + - [ ] make it enabled/disabled based on general flag + - [ ] cleanup internals +- [ ] review & change general component insertion & spawning ordering & logic + - GltfComponentsSet::Injection => GltfBlueprintsSet::Spawn => GltfBlueprintsSet::AfterSpawn + Injection => inject lights & co => spawn => afterSpawn + => Injection => inject lights & co + - [ ] add a way of overriding assets for collection instances => doubt this is possible - [ ] cleanup all the spurious debug messages - [ ] fix animation handling