feat(gltf_blueprints): basics of functional dynamic loading of sub_blueprints

This commit is contained in:
kaosat.dev 2024-03-11 14:41:43 +01:00
parent 6f93b6e55a
commit 3dd3557f53
3 changed files with 163 additions and 16 deletions

View File

@ -144,7 +144,10 @@ impl Plugin for BlueprintsPlugin {
.add_systems( .add_systems(
Update, Update,
( (
spawn_from_blueprints, (spawn_from_blueprints,
check_for_loaded,
actually_spawn_stuff, apply_deferred).chain(),
compute_scene_aabbs.run_if(aabbs_enabled), compute_scene_aabbs.run_if(aabbs_enabled),
apply_deferred.run_if(aabbs_enabled), apply_deferred.run_if(aabbs_enabled),
apply_deferred, apply_deferred,

View File

@ -51,9 +51,150 @@ pub(crate) struct OriginalChildren(pub Vec<Entity>);
#[reflect(Component)] #[reflect(Component)]
pub struct BlueprintsList(pub HashMap<String,Vec<String>>); pub struct BlueprintsList(pub HashMap<String,Vec<String>>);
/// main spawning functions,
#[derive(Reflect, Default, Debug)]
pub(crate) struct BlueprintLoadTracker{
pub name: String,
pub id: AssetId<Gltf>,
pub loaded: bool,
pub handle: Handle<Gltf>
}
#[derive(Component, Default, Debug)]
pub(crate) struct BlueprintAssetsToLoad{
pub all_loaded: bool,
pub asset_infos: Vec<BlueprintLoadTracker>,
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 /// * also takes into account the already exisiting "override" components, ie "override components" > components from blueprint
pub(crate) fn spawn_from_blueprints( pub(crate) fn spawn_from_blueprints(
spawn_placeholders: Query<
(
Entity,
&BlueprintName,
Option<&Parent>,
Option<&Library>,
Option<&Name>,
Option<&BlueprintsList>,
// Option<&BlueprintAssetsPreloaded>
),
(Added<BlueprintName>, Added<SpawnHere>, Without<Spawned>),
>,
mut commands: Commands,
asset_server: Res<AssetServer>,
blueprints_config: Res<BluePrintsConfig>,
) {
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<BlueprintLoadTracker> = 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<Gltf> = 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<BlueprintAssetsNotLoaded>>,
asset_server: Res<AssetServer>,
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::<BlueprintAssetsNotLoaded>();
}
}
}
pub(crate) fn actually_spawn_stuff(
spawn_placeholders: Query< spawn_placeholders: Query<
( (
Entity, Entity,
@ -64,7 +205,7 @@ pub(crate) fn spawn_from_blueprints(
Option<&AddToGameWorld>, Option<&AddToGameWorld>,
Option<&Name>, Option<&Name>,
), ),
(Added<BlueprintName>, Added<SpawnHere>, Without<Spawned>), (With<BlueprintAssetsLoaded>, Added<BlueprintAssetsLoaded>, Without<BlueprintAssetsNotLoaded>),
>, >,
mut commands: Commands, mut commands: Commands,
@ -76,6 +217,8 @@ pub(crate) fn spawn_from_blueprints(
children: Query<&Children>, children: Query<&Children>,
){ ){
for ( for (
entity, entity,
blupeprint_name, blupeprint_name,
@ -84,20 +227,14 @@ pub(crate) fn spawn_from_blueprints(
library_override, library_override,
add_to_world, add_to_world,
name, name,
) in spawn_placeholders.iter() ) in spawn_placeholders.iter()
{ {
debug!( info!(
"need to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}", "need to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}",
blupeprint_name.0, name, entity, original_parent blupeprint_name.0, name, entity, original_parent
); );
let mut original_children: Vec<Entity> = vec![];
if let Ok(c) = children.get(entity) {
for child in c.iter() {
original_children.push(*child);
}
}
let what = &blupeprint_name.0; let what = &blupeprint_name.0;
let model_file_name = format!("{}.{}", &what, &blueprints_config.format); 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); 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())); 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<Gltf> = asset_server.load(model_path); let model_handle: Handle<Gltf> = asset_server.load(model_path);
let gltf = assets_gltf let gltf = assets_gltf
@ -128,6 +265,12 @@ pub(crate) fn spawn_from_blueprints(
transforms = *transform.unwrap(); transforms = *transform.unwrap();
} }
let mut original_children: Vec<Entity> = vec![];
if let Ok(c) = children.get(entity) {
for child in c.iter() {
original_children.push(*child);
}
}
commands.entity(entity).insert(( commands.entity(entity).insert((
SceneBundle { SceneBundle {
scene: scene.clone(), scene: scene.clone(),

View File

@ -6,7 +6,7 @@ use bevy::scene::SceneInstance;
use super::{AnimationPlayerLink, Animations}; use super::{AnimationPlayerLink, Animations};
use super::{SpawnHere, Spawned}; 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 /// 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 /// - it removes one level of useless nesting
@ -89,6 +89,7 @@ pub(crate) fn spawned_blueprint_post_process(
commands.entity(original).remove::<SpawnHere>(); commands.entity(original).remove::<SpawnHere>();
commands.entity(original).remove::<Spawned>(); commands.entity(original).remove::<Spawned>();
commands.entity(original).remove::<Handle<Scene>>(); commands.entity(original).remove::<Handle<Scene>>();
commands.entity(original).remove::<BlueprintAssetsToLoad>();// 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(); commands.entity(root_entity).despawn_recursive();
} }
} }