From 3dd3557f53caa532eae178b1dbe0db0d47212bb9 Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Mon, 11 Mar 2024 14:41:43 +0100 Subject: [PATCH] feat(gltf_blueprints): basics of functional dynamic loading of sub_blueprints --- crates/bevy_gltf_blueprints/src/lib.rs | 5 +- .../src/spawn_from_blueprints.rs | 171 ++++++++++++++++-- .../src/spawn_post_process.rs | 3 +- 3 files changed, 163 insertions(+), 16 deletions(-) diff --git a/crates/bevy_gltf_blueprints/src/lib.rs b/crates/bevy_gltf_blueprints/src/lib.rs index 5f4f89a..0b8e2f6 100644 --- a/crates/bevy_gltf_blueprints/src/lib.rs +++ b/crates/bevy_gltf_blueprints/src/lib.rs @@ -144,7 +144,10 @@ impl Plugin for BlueprintsPlugin { .add_systems( Update, ( - spawn_from_blueprints, + (spawn_from_blueprints, + check_for_loaded, + actually_spawn_stuff, apply_deferred).chain(), + compute_scene_aabbs.run_if(aabbs_enabled), apply_deferred.run_if(aabbs_enabled), apply_deferred, diff --git a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs index c9b03a9..f896723 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs @@ -51,22 +51,163 @@ pub(crate) struct OriginalChildren(pub Vec); #[reflect(Component)] pub struct BlueprintsList(pub HashMap>); -/// main spawning functions, + +#[derive(Reflect, Default, Debug)] +pub(crate) struct BlueprintLoadTracker{ + pub name: String, + pub id: AssetId, + pub loaded: bool, + pub handle: Handle +} +#[derive(Component, Default, Debug)] +pub(crate) struct BlueprintAssetsToLoad{ + pub all_loaded: bool, + pub asset_infos: Vec, + pub progress: f32 +} + +/// flag component +#[derive(Component)] +pub(crate) struct BlueprintAssetsLoaded; +/// flag component +#[derive(Component)] +pub(crate) struct BlueprintAssetsNotLoaded; + +/// spawning prepare function, /// * also takes into account the already exisiting "override" components, ie "override components" > components from blueprint pub(crate) fn spawn_from_blueprints( spawn_placeholders: Query< ( Entity, &BlueprintName, - Option<&Transform>, Option<&Parent>, Option<&Library>, - Option<&AddToGameWorld>, Option<&Name>, + + Option<&BlueprintsList>, + // Option<&BlueprintAssetsPreloaded> + ), (Added, Added, Without), >, + mut commands: Commands, + asset_server: Res, + blueprints_config: Res, +) { + for ( + entity, + blupeprint_name, + original_parent, + library_override, + name, + + blueprints_list, + ) in spawn_placeholders.iter() + { + debug!( + "preparing to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}", + blupeprint_name.0, name, entity, original_parent + ); + + // println!("main model path {:?}", model_path); + if blueprints_list.is_some() { + let blueprints_list = blueprints_list.unwrap(); + // println!("blueprints list {:?}", blueprints_list.0.keys()); + + let mut asset_infos:Vec = vec![]; + for (blueprint_name, _) in blueprints_list.0.iter() { + /*if blueprint_name == what { + println!("WHOLY MOLLY !") + }*/ + // println!("library path {:?}", library_path); + let mut library_path = &blueprints_config.library_folder; // TODO: we cannot use the overriden library path + // FIXME: hack + if blueprint_name == "World" { + library_path= &library_override.unwrap().0; + } + + let model_file_name = format!("{}.{}", &blueprint_name, &blueprints_config.format); + let model_path = Path::new(&library_path).join(Path::new(model_file_name.as_str())); + + let model_handle: Handle = asset_server.load(model_path.clone()); + let model_id = model_handle.id(); + let loaded = asset_server.is_loaded_with_dependencies(model_id); + if !loaded { + asset_infos.push(BlueprintLoadTracker{ + name: model_path.to_string_lossy().into(), + id: model_id, + loaded: false, + handle: model_handle.clone() + }); + } + } + // if not all assets are already loaded, inject a component to signal that we need them to be loaded + if asset_infos.len() > 0 { + commands + .entity(entity) + .insert(BlueprintAssetsToLoad{ + all_loaded: false, + asset_infos: asset_infos, + ..Default::default() + }) + .insert(BlueprintAssetsNotLoaded); + }else { + commands + .entity(entity) + .insert(BlueprintAssetsLoaded); + } + } + } +} + + +pub(crate) fn check_for_loaded( + mut blueprint_assets_to_load: Query<(Entity, &mut BlueprintAssetsToLoad),With>, + asset_server: Res, + mut commands: Commands, +){ + for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut(){ + let mut all_loaded = true; + let mut loaded_amount = 0; + let total = assets_to_load.asset_infos.len(); + for tracker in assets_to_load.asset_infos.iter_mut(){ + let asset_id = tracker.id; + let loaded = asset_server.is_loaded_with_dependencies(asset_id); + tracker.loaded = loaded; + if loaded { + loaded_amount += 1; + }else{ + all_loaded = false; + } + } + let progress:f32 = loaded_amount as f32 / total as f32; + println!("progress: {}",progress); + assets_to_load.progress = progress; + + if all_loaded { + assets_to_load.all_loaded = true; + commands.entity(entity) + .insert(BlueprintAssetsLoaded) + .remove::(); + } + } +} + +pub(crate) fn actually_spawn_stuff( + spawn_placeholders: Query< + ( + Entity, + &BlueprintName, + Option<&Transform>, + Option<&Parent>, + Option<&Library>, + Option<&AddToGameWorld>, + Option<&Name>, + ), + (With, Added, Without), + >, + mut commands: Commands, mut game_world: Query>, @@ -75,7 +216,9 @@ pub(crate) fn spawn_from_blueprints( blueprints_config: Res, children: Query<&Children>, -) { +){ + + for ( entity, blupeprint_name, @@ -84,20 +227,14 @@ pub(crate) fn spawn_from_blueprints( library_override, add_to_world, name, + ) in spawn_placeholders.iter() { - debug!( + info!( "need to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}", blupeprint_name.0, name, entity, original_parent ); - let mut original_children: Vec = vec![]; - if let Ok(c) = children.get(entity) { - for child in c.iter() { - original_children.push(*child); - } - } - let what = &blupeprint_name.0; let model_file_name = format!("{}.{}", &what, &blueprints_config.format); @@ -106,7 +243,7 @@ pub(crate) fn spawn_from_blueprints( library_override.map_or_else(|| &blueprints_config.library_folder, |l| &l.0); let model_path = Path::new(&library_path).join(Path::new(model_file_name.as_str())); - debug!("attempting to spawn {:?}", model_path); + info!("attempting to spawn {:?}", model_path); let model_handle: Handle = asset_server.load(model_path); let gltf = assets_gltf @@ -128,6 +265,12 @@ pub(crate) fn spawn_from_blueprints( transforms = *transform.unwrap(); } + let mut original_children: Vec = vec![]; + if let Ok(c) = children.get(entity) { + for child in c.iter() { + original_children.push(*child); + } + } commands.entity(entity).insert(( SceneBundle { scene: scene.clone(), @@ -148,4 +291,4 @@ pub(crate) fn spawn_from_blueprints( commands.entity(world).add_child(entity); } } -} +} \ No newline at end of file diff --git a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs index 2caa625..ef12350 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs @@ -6,7 +6,7 @@ use bevy::scene::SceneInstance; use super::{AnimationPlayerLink, Animations}; use super::{SpawnHere, Spawned}; -use crate::{CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren}; +use crate::{BlueprintAssetsToLoad, CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren}; /// this system is in charge of doing any necessary post processing after a blueprint scene has been spawned /// - it removes one level of useless nesting @@ -89,6 +89,7 @@ pub(crate) fn spawned_blueprint_post_process( commands.entity(original).remove::(); commands.entity(original).remove::(); commands.entity(original).remove::>(); + 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(root_entity).despawn_recursive(); } }