Merge f5b063cd34
into 1353e14802
This commit is contained in:
commit
d83b281c0b
|
@ -120,6 +120,10 @@ impl Plugin for BlueprintsPlugin {
|
||||||
.register_type::<MaterialInfo>()
|
.register_type::<MaterialInfo>()
|
||||||
.register_type::<SpawnHere>()
|
.register_type::<SpawnHere>()
|
||||||
.register_type::<Animations>()
|
.register_type::<Animations>()
|
||||||
|
.register_type::<BlueprintsList>()
|
||||||
|
.register_type::<Vec<String>>()
|
||||||
|
.register_type::<HashMap<String,Vec<String>>>()
|
||||||
|
|
||||||
.insert_resource(BluePrintsConfig {
|
.insert_resource(BluePrintsConfig {
|
||||||
format: self.format,
|
format: self.format,
|
||||||
library_folder: self.library_folder.clone(),
|
library_folder: self.library_folder.clone(),
|
||||||
|
@ -140,11 +144,29 @@ impl Plugin for BlueprintsPlugin {
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(
|
(
|
||||||
spawn_from_blueprints,
|
(
|
||||||
compute_scene_aabbs.run_if(aabbs_enabled),
|
prepare_blueprints,
|
||||||
apply_deferred.run_if(aabbs_enabled),
|
check_for_loaded,
|
||||||
|
spawn_from_blueprints,
|
||||||
|
apply_deferred
|
||||||
|
)
|
||||||
|
.chain(),
|
||||||
|
(
|
||||||
|
compute_scene_aabbs,
|
||||||
|
apply_deferred
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
|
.run_if(aabbs_enabled),
|
||||||
|
|
||||||
apply_deferred,
|
apply_deferred,
|
||||||
materials_inject.run_if(materials_library_enabled),
|
|
||||||
|
(
|
||||||
|
materials_inject,
|
||||||
|
check_for_material_loaded,
|
||||||
|
materials_inject2
|
||||||
|
)
|
||||||
|
.chain()
|
||||||
|
.run_if(materials_library_enabled),
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
.in_set(GltfBlueprintsSet::Spawn),
|
.in_set(GltfBlueprintsSet::Spawn),
|
||||||
|
|
|
@ -1,22 +1,19 @@
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::{AssetServer, Assets, Handle},
|
asset::{AssetId, AssetServer, Assets, Handle},
|
||||||
ecs::{
|
ecs::{
|
||||||
component::Component,
|
component::Component, entity::Entity, query::{Added, With}, reflect::ReflectComponent, system::{Commands, Query, Res, ResMut}
|
||||||
query::{Added, With},
|
|
||||||
reflect::ReflectComponent,
|
|
||||||
system::{Commands, Query, Res, ResMut},
|
|
||||||
},
|
},
|
||||||
gltf::Gltf,
|
gltf::Gltf,
|
||||||
hierarchy::{Children, Parent},
|
hierarchy::{Children, Parent},
|
||||||
log::debug,
|
log::{debug, info},
|
||||||
pbr::StandardMaterial,
|
pbr::StandardMaterial,
|
||||||
reflect::Reflect,
|
reflect::Reflect,
|
||||||
render::mesh::Mesh,
|
render::mesh::Mesh,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::BluePrintsConfig;
|
use crate::{AssetLoadTracker, AssetsToLoad, BluePrintsConfig};
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
|
@ -26,10 +23,105 @@ pub struct MaterialInfo {
|
||||||
pub source: String,
|
pub source: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// flag component
|
||||||
|
#[derive(Component)]
|
||||||
|
pub(crate) struct BlueprintMaterialAssetsLoaded;
|
||||||
|
/// flag component
|
||||||
|
#[derive(Component)]
|
||||||
|
pub(crate) struct BlueprintMaterialAssetsNotLoaded;
|
||||||
|
|
||||||
/// system that injects / replaces materials from material library
|
/// system that injects / replaces materials from material library
|
||||||
pub(crate) fn materials_inject(
|
pub(crate) fn materials_inject(
|
||||||
|
blueprints_config: ResMut<BluePrintsConfig>,
|
||||||
|
material_infos: Query<(Entity, &MaterialInfo), Added<MaterialInfo>>,
|
||||||
|
asset_server: Res<AssetServer>,
|
||||||
|
mut commands: Commands,
|
||||||
|
) {
|
||||||
|
for (entity, material_info) in material_infos.iter() {
|
||||||
|
let model_file_name = format!(
|
||||||
|
"{}_materials_library.{}",
|
||||||
|
&material_info.source, &blueprints_config.format
|
||||||
|
);
|
||||||
|
let materials_path = Path::new(&blueprints_config.material_library_folder)
|
||||||
|
.join(Path::new(model_file_name.as_str()));
|
||||||
|
let material_name = &material_info.name;
|
||||||
|
let material_full_path = materials_path.to_str().unwrap().to_string() + "#" + material_name; // TODO: yikes, cleanup
|
||||||
|
|
||||||
|
if blueprints_config
|
||||||
|
.material_library_cache
|
||||||
|
.contains_key(&material_full_path)
|
||||||
|
{
|
||||||
|
debug!("material is cached, retrieving");
|
||||||
|
blueprints_config
|
||||||
|
.material_library_cache
|
||||||
|
.get(&material_full_path)
|
||||||
|
.expect("we should have the material available");
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BlueprintMaterialAssetsLoaded);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let material_file_handle: Handle<Gltf> = asset_server.load(materials_path.clone());
|
||||||
|
let material_file_id = material_file_handle.id();
|
||||||
|
let mut asset_infos:Vec<AssetLoadTracker<Gltf>> = vec![];
|
||||||
|
|
||||||
|
asset_infos.push(AssetLoadTracker {
|
||||||
|
name: material_full_path,
|
||||||
|
id: material_file_id,
|
||||||
|
loaded: false,
|
||||||
|
handle: material_file_handle.clone()
|
||||||
|
});
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(AssetsToLoad{
|
||||||
|
all_loaded: false,
|
||||||
|
asset_infos: asset_infos,
|
||||||
|
progress: 0.0
|
||||||
|
//..Default::default()
|
||||||
|
})
|
||||||
|
.insert(BlueprintMaterialAssetsNotLoaded);
|
||||||
|
/**/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO, merge with check_for_loaded, make generic ?
|
||||||
|
pub(crate) fn check_for_material_loaded(
|
||||||
|
mut blueprint_assets_to_load: Query<(Entity, &mut AssetsToLoad<Gltf>),With<BlueprintMaterialAssetsNotLoaded>>,
|
||||||
|
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;
|
||||||
|
assets_to_load.progress = progress;
|
||||||
|
|
||||||
|
if all_loaded {
|
||||||
|
assets_to_load.all_loaded = true;
|
||||||
|
commands.entity(entity)
|
||||||
|
.insert(BlueprintMaterialAssetsLoaded)
|
||||||
|
.remove::<BlueprintMaterialAssetsNotLoaded>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// system that injects / replaces materials from material library
|
||||||
|
pub(crate) fn materials_inject2(
|
||||||
mut blueprints_config: ResMut<BluePrintsConfig>,
|
mut blueprints_config: ResMut<BluePrintsConfig>,
|
||||||
material_infos: Query<(&MaterialInfo, &Children), Added<MaterialInfo>>,
|
material_infos: Query<(&MaterialInfo, &Children, ), (Added<BlueprintMaterialAssetsLoaded>, With<BlueprintMaterialAssetsLoaded>)>,
|
||||||
with_materials_and_meshes: Query<
|
with_materials_and_meshes: Query<
|
||||||
(),
|
(),
|
||||||
(
|
(
|
||||||
|
@ -38,9 +130,9 @@ pub(crate) fn materials_inject(
|
||||||
With<Handle<Mesh>>,
|
With<Handle<Mesh>>,
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
models: Res<Assets<bevy::gltf::Gltf>>,
|
assets_gltf: Res<Assets<Gltf>>,
|
||||||
|
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for (material_info, children) in material_infos.iter() {
|
for (material_info, children) in material_infos.iter() {
|
||||||
|
@ -65,10 +157,10 @@ pub(crate) fn materials_inject(
|
||||||
.get(&material_full_path)
|
.get(&material_full_path)
|
||||||
.expect("we should have the material available");
|
.expect("we should have the material available");
|
||||||
material_found = Some(material);
|
material_found = Some(material);
|
||||||
} else {
|
}else {
|
||||||
let my_gltf: Handle<Gltf> = asset_server.load(materials_path.clone());
|
let model_handle: Handle<Gltf> = asset_server.load(materials_path.clone());// FIXME: kinda weird now
|
||||||
let mat_gltf = models
|
let mat_gltf = assets_gltf
|
||||||
.get(my_gltf.id())
|
.get(model_handle.id())
|
||||||
.expect("material should have been preloaded");
|
.expect("material should have been preloaded");
|
||||||
if mat_gltf.named_materials.contains_key(material_name) {
|
if mat_gltf.named_materials.contains_key(material_name) {
|
||||||
let material = mat_gltf
|
let material = mat_gltf
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use bevy::{gltf::Gltf, prelude::*};
|
use bevy::{gltf::Gltf, prelude::*, utils::HashMap};
|
||||||
|
|
||||||
use crate::{Animations, BluePrintsConfig};
|
use crate::{Animations, BluePrintsConfig};
|
||||||
|
|
||||||
|
@ -46,22 +46,169 @@ pub struct AddToGameWorld;
|
||||||
/// helper component, just to transfer child data
|
/// helper component, just to transfer child data
|
||||||
pub(crate) struct OriginalChildren(pub Vec<Entity>);
|
pub(crate) struct OriginalChildren(pub Vec<Entity>);
|
||||||
|
|
||||||
/// main spawning functions,
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
|
#[reflect(Component)]
|
||||||
|
pub struct BlueprintsList(pub HashMap<String,Vec<String>>);
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub(crate) struct AssetLoadTracker<T:bevy::prelude::Asset>{
|
||||||
|
pub name: String,
|
||||||
|
pub id: AssetId<T>,
|
||||||
|
pub loaded: bool,
|
||||||
|
pub handle: Handle<T>
|
||||||
|
}
|
||||||
|
#[derive(Component, Default, Debug)]
|
||||||
|
pub(crate) struct AssetsToLoad<T:bevy::prelude::Asset>{
|
||||||
|
pub all_loaded: bool,
|
||||||
|
pub asset_infos: Vec<AssetLoadTracker<T>>,
|
||||||
|
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 prepare_blueprints(
|
||||||
spawn_placeholders: Query<
|
spawn_placeholders: Query<
|
||||||
(
|
(
|
||||||
Entity,
|
Entity,
|
||||||
&BlueprintName,
|
&BlueprintName,
|
||||||
Option<&Transform>,
|
|
||||||
Option<&Parent>,
|
Option<&Parent>,
|
||||||
Option<&Library>,
|
Option<&Library>,
|
||||||
Option<&AddToGameWorld>,
|
|
||||||
Option<&Name>,
|
Option<&Name>,
|
||||||
|
Option<&BlueprintsList>,
|
||||||
),
|
),
|
||||||
(Added<BlueprintName>, Added<SpawnHere>, Without<Spawned>),
|
(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!(
|
||||||
|
"requesting 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<AssetLoadTracker<Gltf>> = 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(AssetLoadTracker {
|
||||||
|
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(AssetsToLoad{
|
||||||
|
all_loaded: false,
|
||||||
|
asset_infos: asset_infos,
|
||||||
|
progress: 0.0
|
||||||
|
//..Default::default()
|
||||||
|
})
|
||||||
|
.insert(BlueprintAssetsNotLoaded);
|
||||||
|
}else {
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BlueprintAssetsLoaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // in case there are no blueprintsList
|
||||||
|
commands
|
||||||
|
.entity(entity)
|
||||||
|
.insert(BlueprintAssetsLoaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn check_for_loaded(
|
||||||
|
mut blueprint_assets_to_load: Query<(Entity, &mut AssetsToLoad<Gltf>), 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 spawn_from_blueprints(
|
||||||
|
spawn_placeholders: Query<
|
||||||
|
(
|
||||||
|
Entity,
|
||||||
|
&BlueprintName,
|
||||||
|
Option<&Transform>,
|
||||||
|
Option<&Parent>,
|
||||||
|
Option<&Library>,
|
||||||
|
Option<&AddToGameWorld>,
|
||||||
|
Option<&Name>,
|
||||||
|
),
|
||||||
|
(With<BlueprintAssetsLoaded>, Added<BlueprintAssetsLoaded>, Without<BlueprintAssetsNotLoaded>),
|
||||||
|
>,
|
||||||
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut game_world: Query<Entity, With<GameWorldTag>>,
|
mut game_world: Query<Entity, With<GameWorldTag>>,
|
||||||
|
|
||||||
|
@ -70,7 +217,8 @@ pub(crate) fn spawn_from_blueprints(
|
||||||
blueprints_config: Res<BluePrintsConfig>,
|
blueprints_config: Res<BluePrintsConfig>,
|
||||||
|
|
||||||
children: Query<&Children>,
|
children: Query<&Children>,
|
||||||
) {
|
){
|
||||||
|
|
||||||
for (
|
for (
|
||||||
entity,
|
entity,
|
||||||
blupeprint_name,
|
blupeprint_name,
|
||||||
|
@ -79,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:{:?}",
|
"attempting 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);
|
||||||
|
|
||||||
|
@ -101,8 +243,8 @@ 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);// FIXME: kinda weird now
|
||||||
|
|
||||||
let gltf = assets_gltf
|
let gltf = assets_gltf
|
||||||
.get(&model_handle)
|
.get(&model_handle)
|
||||||
|
@ -123,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(),
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
|
use bevy::gltf::Gltf;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::scene::SceneInstance;
|
use bevy::scene::SceneInstance;
|
||||||
// use bevy::utils::hashbrown::HashSet;
|
// use bevy::utils::hashbrown::HashSet;
|
||||||
|
|
||||||
use super::{AnimationPlayerLink, Animations};
|
use super::{AnimationPlayerLink, Animations};
|
||||||
use super::{SpawnHere, Spawned};
|
use super::{SpawnHere, Spawned};
|
||||||
use crate::{CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren};
|
use crate::{AssetsToLoad, BlueprintAssetsLoaded, 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 +90,8 @@ 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::<AssetsToLoad<Gltf>>();// 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::<BlueprintAssetsLoaded>();
|
||||||
commands.entity(root_entity).despawn_recursive();
|
commands.entity(root_entity).despawn_recursive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ pub fn setup_game(
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
scene: models
|
scene: models
|
||||||
.get(game_assets.world.id())
|
.get(game_assets.world.clone().unwrap().id())
|
||||||
.expect("main level should have been loaded")
|
.expect("main level should have been loaded")
|
||||||
.scenes[0]
|
.scenes[0]
|
||||||
.clone(),
|
.clone(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn setup_game(
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
scene: models
|
scene: models
|
||||||
.get(game_assets.world.id())
|
.get(game_assets.world.clone().unwrap().id())
|
||||||
.expect("main level should have been loaded")
|
.expect("main level should have been loaded")
|
||||||
.scenes[0]
|
.scenes[0]
|
||||||
.clone(),
|
.clone(),
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub fn setup_game(
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
scene: models
|
scene: models
|
||||||
.get(game_assets.world.id())
|
.get(game_assets.world.clone().unwrap().id())
|
||||||
.expect("main level should have been loaded")
|
.expect("main level should have been loaded")
|
||||||
.scenes[0]
|
.scenes[0]
|
||||||
.clone(),
|
.clone(),
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn setup_game(
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
scene: models
|
scene: models
|
||||||
.get(game_assets.world.id())
|
.get(game_assets.world.clone().unwrap().id())
|
||||||
.expect("main level should have been loaded")
|
.expect("main level should have been loaded")
|
||||||
.scenes[0]
|
.scenes[0]
|
||||||
.clone(),
|
.clone(),
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn setup_game(
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
scene: models
|
scene: models
|
||||||
.get(game_assets.world.id())
|
.get(game_assets.world.clone().unwrap().id())
|
||||||
.expect("main level should have been loaded")
|
.expect("main level should have been loaded")
|
||||||
.scenes[0]
|
.scenes[0]
|
||||||
.clone(),
|
.clone(),
|
||||||
|
|
|
@ -76,7 +76,7 @@ pub fn trigger_level_transition(
|
||||||
} else if target_level == "Level2" {
|
} else if target_level == "Level2" {
|
||||||
level = game_assets.level2.clone().unwrap();
|
level = game_assets.level2.clone().unwrap();
|
||||||
} else {
|
} else {
|
||||||
level = game_assets.world.clone();
|
level = game_assets.world.clone().unwrap();
|
||||||
}
|
}
|
||||||
info!("spawning new level");
|
info!("spawning new level");
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub fn setup_game(
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
||||||
scene: models
|
scene: models
|
||||||
.get(game_assets.world.id())
|
.get(game_assets.world.clone().unwrap().id())
|
||||||
.expect("main level should have been loaded")
|
.expect("main level should have been loaded")
|
||||||
.scenes[0]
|
.scenes[0]
|
||||||
.clone(),
|
.clone(),
|
||||||
|
|
|
@ -5,8 +5,8 @@ use bevy_asset_loader::prelude::*;
|
||||||
|
|
||||||
#[derive(AssetCollection, Resource)]
|
#[derive(AssetCollection, Resource)]
|
||||||
pub struct GameAssets {
|
pub struct GameAssets {
|
||||||
#[asset(key = "world")]
|
#[asset(key = "world", optional)]
|
||||||
pub world: Handle<Gltf>,
|
pub world: Option<Handle<Gltf>>,
|
||||||
|
|
||||||
#[asset(key = "world_dynamic", optional)]
|
#[asset(key = "world_dynamic", optional)]
|
||||||
pub world_dynamic: Option<Handle<Gltf>>,
|
pub world_dynamic: Option<Handle<Gltf>>,
|
||||||
|
@ -16,8 +16,8 @@ pub struct GameAssets {
|
||||||
#[asset(key = "level2", optional)]
|
#[asset(key = "level2", optional)]
|
||||||
pub level2: Option<Handle<Gltf>>,
|
pub level2: Option<Handle<Gltf>>,
|
||||||
|
|
||||||
#[asset(key = "models", collection(typed, mapped))]
|
#[asset(key = "models", collection(typed, mapped), optional)]
|
||||||
pub models: HashMap<String, Handle<Gltf>>,
|
pub models: Option<HashMap<String, Handle<Gltf>>>,
|
||||||
|
|
||||||
#[asset(key = "materials", collection(typed, mapped), optional)]
|
#[asset(key = "materials", collection(typed, mapped), optional)]
|
||||||
pub materials: Option<HashMap<String, Handle<Gltf>>>,
|
pub materials: Option<HashMap<String, Handle<Gltf>>>,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
({
|
({
|
||||||
"world":File (path: "models/World.glb"),
|
/*"world":File (path: "models/World.glb"),
|
||||||
"models": Folder (
|
"models": Folder (
|
||||||
path: "models/library",
|
path: "models/library",
|
||||||
),
|
),*/
|
||||||
})
|
})
|
|
@ -11,6 +11,7 @@ impl Plugin for CorePlugin {
|
||||||
legacy_mode: false,
|
legacy_mode: false,
|
||||||
library_folder: "models/library".into(),
|
library_folder: "models/library".into(),
|
||||||
format: GltfFormat::GLB,
|
format: GltfFormat::GLB,
|
||||||
|
material_library:true,
|
||||||
aabbs: true,
|
aabbs: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use bevy::prelude::*;
|
use bevy::{prelude::*, utils::hashbrown::HashMap};
|
||||||
use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, GameWorldTag};
|
use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, BlueprintsList, GameWorldTag, Library, SpawnHere};
|
||||||
use bevy_gltf_worlflow_examples_common_rapier::{assets::GameAssets, GameState, InAppRunning};
|
use bevy_gltf_worlflow_examples_common_rapier::{assets::GameAssets, GameState, InAppRunning};
|
||||||
|
|
||||||
use bevy_rapier3d::prelude::Velocity;
|
use bevy_rapier3d::prelude::Velocity;
|
||||||
|
@ -7,31 +7,19 @@ use rand::Rng;
|
||||||
|
|
||||||
pub fn setup_game(
|
pub fn setup_game(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
game_assets: Res<GameAssets>,
|
asset_server: Res<AssetServer>,
|
||||||
models: Res<Assets<bevy::gltf::Gltf>>,
|
|
||||||
mut next_game_state: ResMut<NextState<GameState>>,
|
mut next_game_state: ResMut<NextState<GameState>>,
|
||||||
) {
|
) {
|
||||||
commands.insert_resource(AmbientLight {
|
|
||||||
color: Color::WHITE,
|
|
||||||
brightness: 0.2,
|
|
||||||
});
|
|
||||||
// here we actually spawn our game world/level
|
// here we actually spawn our game world/level
|
||||||
|
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
SceneBundle {
|
SceneBundle{
|
||||||
// note: because of this issue https://github.com/bevyengine/bevy/issues/10436, "world" is now a gltf file instead of a scene
|
scene: asset_server.load("models/World.glb#Scene0"),
|
||||||
scene: models
|
|
||||||
.get(game_assets.world.id())
|
|
||||||
.expect("main level should have been loaded")
|
|
||||||
.scenes[0]
|
|
||||||
.clone(),
|
|
||||||
..default()
|
..default()
|
||||||
},
|
},
|
||||||
bevy::prelude::Name::from("world"),
|
bevy::prelude::Name::from("world"),
|
||||||
GameWorldTag,
|
GameWorldTag,
|
||||||
InAppRunning,
|
InAppRunning,
|
||||||
));
|
));
|
||||||
|
|
||||||
next_game_state.set(GameState::InGame)
|
next_game_state.set(GameState::InGame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,13 +97,15 @@ impl Plugin for GamePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Update, (spawn_test).run_if(in_state(GameState::InGame)))
|
app.add_systems(Update, (spawn_test).run_if(in_state(GameState::InGame)))
|
||||||
.add_systems(Update, validate_export)
|
.add_systems(Update, validate_export)
|
||||||
.add_systems(Update, generate_screenshot.run_if(on_timer(Duration::from_secs_f32(0.2)))) // TODO: run once
|
|
||||||
.add_systems(OnEnter(AppState::MenuRunning), start_game)
|
.add_systems(OnEnter(AppState::MenuRunning), start_game)
|
||||||
.add_systems(OnEnter(AppState::AppRunning), setup_game)
|
.add_systems(OnEnter(AppState::AppRunning), setup_game)
|
||||||
|
/* .add_systems(Update, generate_screenshot.run_if(on_timer(Duration::from_secs_f32(0.2)))) // TODO: run once
|
||||||
|
|
||||||
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
exit_game.run_if(on_timer(Duration::from_secs_f32(0.5))),
|
exit_game.run_if(on_timer(Duration::from_secs_f32(0.5))),
|
||||||
) // shut down the app after this time
|
) // shut down the app after this time*/
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import bpy
|
||||||
from ..helpers.generate_and_export import generate_and_export
|
from ..helpers.generate_and_export import generate_and_export
|
||||||
from .export_gltf import (generate_gltf_export_preferences, export_gltf)
|
from .export_gltf import (generate_gltf_export_preferences, export_gltf)
|
||||||
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
|
from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
|
||||||
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
|
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into, inject_blueprints_list_into_main_scene
|
||||||
|
|
||||||
|
|
||||||
# export all main scenes
|
# export all main scenes
|
||||||
|
@ -29,6 +29,8 @@ def export_main_scene(scene, folder_path, addon_prefs, library_collections):
|
||||||
}
|
}
|
||||||
|
|
||||||
if export_blueprints :
|
if export_blueprints :
|
||||||
|
inject_blueprints_list_into_main_scene(scene)
|
||||||
|
|
||||||
if export_separate_dynamic_and_static_objects:
|
if export_separate_dynamic_and_static_objects:
|
||||||
#print("SPLIT STATIC AND DYNAMIC")
|
#print("SPLIT STATIC AND DYNAMIC")
|
||||||
# first export static objects
|
# first export static objects
|
||||||
|
|
|
@ -36,16 +36,23 @@ def get_marked_collections(scene, addon_prefs):
|
||||||
return (collection_names, marked_collections)
|
return (collection_names, marked_collections)
|
||||||
|
|
||||||
# gets all collections within collections that might also be relevant
|
# gets all collections within collections that might also be relevant
|
||||||
def get_sub_collections(collections, parent, children_per_collection):
|
def get_sub_collections(collections, parent=None, children_per_collection=None):
|
||||||
|
if parent == None:
|
||||||
|
parent = CollectionNode()
|
||||||
|
if children_per_collection == None:
|
||||||
|
children_per_collection = {}
|
||||||
|
|
||||||
collection_names = set()
|
collection_names = set()
|
||||||
used_collections = []
|
used_collections = []
|
||||||
|
|
||||||
for root_collection in collections:
|
for root_collection in collections:
|
||||||
node = Node(name=root_collection.name, parent=parent)
|
print("collections", collections)
|
||||||
|
node = CollectionNode(name=root_collection.name, parent=parent)
|
||||||
parent.children.append(node)
|
parent.children.append(node)
|
||||||
|
|
||||||
#print("root collection", root_collection.name)
|
#print("root collection", root_collection.name)
|
||||||
for collection in traverse_tree(root_collection): # TODO: filter out COLLECTIONS that have the flatten flag (unlike the flatten flag on colleciton instances themselves)
|
for collection in traverse_tree(root_collection): # TODO: filter out COLLECTIONS that have the flatten flag (unlike the flatten flag on colleciton instances themselves)
|
||||||
|
print("sub", collection)
|
||||||
node_name = collection.name
|
node_name = collection.name
|
||||||
children_per_collection[node_name] = []
|
children_per_collection[node_name] = []
|
||||||
#print(" scanning", collection.name)
|
#print(" scanning", collection.name)
|
||||||
|
@ -53,12 +60,17 @@ def get_sub_collections(collections, parent, children_per_collection):
|
||||||
#print("FLATTEN", object.name, 'Flatten' in object)
|
#print("FLATTEN", object.name, 'Flatten' in object)
|
||||||
if object.instance_type == 'COLLECTION' : # and not 'Flatten' in object:
|
if object.instance_type == 'COLLECTION' : # and not 'Flatten' in object:
|
||||||
collection_name = object.instance_collection.name
|
collection_name = object.instance_collection.name
|
||||||
|
print("sub obj", collection_name)
|
||||||
|
# FIXME: not sure:
|
||||||
|
children_per_collection[node_name].append(collection_name)
|
||||||
|
|
||||||
(sub_names, sub_collections) = get_sub_collections([object.instance_collection], node, children_per_collection)
|
(sub_names, sub_collections) = get_sub_collections([object.instance_collection], node, children_per_collection)
|
||||||
|
print("gna", sub_names, sub_collections)
|
||||||
if len(list(sub_names)) > 0:
|
if len(list(sub_names)) > 0:
|
||||||
|
print("toto")
|
||||||
children_per_collection[node_name] += (list(sub_names))
|
children_per_collection[node_name] += (list(sub_names))
|
||||||
#print(" found sub collection in use", object.name, object.instance_collection)
|
#print(" found sub collection in use", object.name, object.instance_collection)
|
||||||
|
|
||||||
|
|
||||||
if not collection_name in collection_names:
|
if not collection_name in collection_names:
|
||||||
collection_names.add(collection_name)
|
collection_names.add(collection_name)
|
||||||
used_collections.append(object.instance_collection)
|
used_collections.append(object.instance_collection)
|
||||||
|
@ -77,7 +89,7 @@ def flatten_collection_tree(node, children_per_collection):
|
||||||
children_per_collection[node.name] = list(set( children_per_collection[node.name]))
|
children_per_collection[node.name] = list(set( children_per_collection[node.name]))
|
||||||
|
|
||||||
|
|
||||||
class Node :
|
class CollectionNode :
|
||||||
def __init__(self, name="", parent=None):
|
def __init__(self, name="", parent=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.children = []
|
self.children = []
|
||||||
|
@ -93,7 +105,7 @@ def get_exportable_collections(main_scenes, library_scenes, addon_prefs):
|
||||||
|
|
||||||
all_collections = []
|
all_collections = []
|
||||||
all_collection_names = []
|
all_collection_names = []
|
||||||
root_node = Node()
|
root_node = CollectionNode()
|
||||||
root_node.name = "root"
|
root_node.name = "root"
|
||||||
children_per_collection = {}
|
children_per_collection = {}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
import json
|
||||||
import bpy
|
import bpy
|
||||||
from .helpers_collections import (set_active_collection)
|
from .helpers_collections import (CollectionNode, get_sub_collections, get_used_collections, set_active_collection)
|
||||||
from .object_makers import (make_empty)
|
from .object_makers import (make_empty)
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,3 +150,40 @@ def get_scenes(addon_prefs):
|
||||||
return [level_scene_names, level_scenes, library_scene_names, library_scenes]
|
return [level_scene_names, level_scenes, library_scene_names, library_scenes]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def inject_blueprints_list_into_main_scene(scene):
|
||||||
|
print("injecting assets data")
|
||||||
|
root_collection = scene.collection
|
||||||
|
assets_list = None
|
||||||
|
for object in scene.objects:
|
||||||
|
if object.name == "assets_list"+scene.name:
|
||||||
|
assets_list = object
|
||||||
|
break
|
||||||
|
|
||||||
|
if assets_list is None:
|
||||||
|
assets_list = make_empty('assets_list_'+scene.name, [0,0,0], [0,0,0], [0,0,0], root_collection)
|
||||||
|
|
||||||
|
|
||||||
|
# find all blueprints used in a scene
|
||||||
|
# TODO: export a tree rather than a flat list ? because you could have potential clashing items in flat lists (amongst other issues)
|
||||||
|
(collection_names, collections) = get_used_collections(scene)
|
||||||
|
root_node = CollectionNode()
|
||||||
|
root_node.name = "root"
|
||||||
|
children_per_collection = {}
|
||||||
|
|
||||||
|
#print("collection_names", collection_names, "collections", collections)
|
||||||
|
(bla, bli ) = get_sub_collections(collections, root_node, children_per_collection)
|
||||||
|
#print("sfdsfsdf", bla, bli, "root", root_node, "children_per_collection", children_per_collection)
|
||||||
|
# with sub collections
|
||||||
|
# (collection_names, collections) = get_sub_collections(all_collections, root_node, children_per_collection)
|
||||||
|
#
|
||||||
|
# what about marked assets ?
|
||||||
|
#assets_list["blueprints_direct"] = list(collection_names)
|
||||||
|
assets_list["BlueprintsList"] = f"({json.dumps(dict(children_per_collection))})"
|
||||||
|
#'({"a":[]})'
|
||||||
|
#'([])'
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
print("assets list", assets_list["BlueprintsList"], children_per_collection)
|
||||||
|
|
|
@ -20,7 +20,7 @@ def setup_data(request):
|
||||||
#other_materials_path = os.path.join("../../testing", "other_materials")
|
#other_materials_path = os.path.join("../../testing", "other_materials")
|
||||||
|
|
||||||
print("\nPerforming teardown...")
|
print("\nPerforming teardown...")
|
||||||
if os.path.exists(models_path):
|
'''if os.path.exists(models_path):
|
||||||
shutil.rmtree(models_path)
|
shutil.rmtree(models_path)
|
||||||
|
|
||||||
"""if os.path.exists(materials_path):
|
"""if os.path.exists(materials_path):
|
||||||
|
@ -34,7 +34,7 @@ def setup_data(request):
|
||||||
|
|
||||||
screenshot_observed_path = os.path.join(root_path, "screenshot.png")
|
screenshot_observed_path = os.path.join(root_path, "screenshot.png")
|
||||||
if os.path.exists(screenshot_observed_path):
|
if os.path.exists(screenshot_observed_path):
|
||||||
os.remove(screenshot_observed_path)
|
os.remove(screenshot_observed_path)'''
|
||||||
|
|
||||||
request.addfinalizer(finalizer)
|
request.addfinalizer(finalizer)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue