feat(Blenvy): basic working loading of levels & assets

* removed/ obsoleted blueprintsList
 * now using AllAssets (meh naming)
 * modified example & internals to enable loading levels as Blueprints as well
 * internals quite messy for now, needs a big cleanup still
 * disabled materials library for now, needs to be overhauled to make use of asset logic as well
 * added more mock assets for testing
 * related changes to blender & bevy side
This commit is contained in:
kaosat.dev 2024-06-09 23:14:49 +02:00
parent 2a74dedcb8
commit 1fdb45bab6
17 changed files with 418 additions and 124 deletions

View File

@ -1,6 +1,6 @@
use std::path::{Path, PathBuf};
use bevy::{gltf::Gltf, prelude::*, utils::HashMap};
use bevy::{asset::LoadedUntypedAsset, gltf::Gltf, prelude::*, utils::HashMap};
use crate::{BluePrintsConfig, BlueprintAnimations};
@ -24,30 +24,35 @@ pub struct AllAssets(pub Vec<MyAsset>);
/// helper component, is used to store the list of sub blueprints to enable automatic loading of dependend blueprints
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
pub struct BlueprintsList(pub HashMap<String, Vec<String>>);
////////////////////////
///
/// flag component, usually added when a blueprint is loaded
#[derive(Component)]
pub(crate) struct BlueprintAssetsLoaded;
/// flag component
#[derive(Component)]
pub(crate) struct BlueprintAssetsNotLoaded;
/// helper component, for tracking loaded assets's loading state, id , handle etc
#[derive(Default, Debug)]
pub(crate) struct AssetLoadTracker<T: bevy::prelude::Asset> {
#[derive(Debug)]
pub(crate) struct AssetLoadTracker {
#[allow(dead_code)]
pub name: String,
pub id: AssetId<T>,
pub id: AssetId<LoadedUntypedAsset>,
pub loaded: bool,
#[allow(dead_code)]
pub handle: Handle<T>,
pub handle: Handle<LoadedUntypedAsset>,
}
/// helper component, for tracking loaded assets
#[derive(Component, Debug)]
pub(crate) struct AssetsToLoad<T: bevy::prelude::Asset> {
pub(crate) struct AssetsToLoad {
pub all_loaded: bool,
pub asset_infos: Vec<AssetLoadTracker<T>>,
pub asset_infos: Vec<AssetLoadTracker>,
pub progress: f32,
}
impl<T: bevy::prelude::Asset> Default for AssetsToLoad<T> {
impl Default for AssetsToLoad {
fn default() -> Self {
Self {
all_loaded: Default::default(),
@ -56,10 +61,3 @@ impl<T: bevy::prelude::Asset> Default for AssetsToLoad<T> {
}
}
}
/// flag component, usually added when a blueprint is loaded
#[derive(Component)]
pub(crate) struct BlueprintAssetsLoaded;
/// flag component
#[derive(Component)]
pub(crate) struct BlueprintAssetsNotLoaded;

View File

@ -129,13 +129,13 @@ impl Plugin for BlueprintsPlugin {
.register_type::<HashMap<u32, Vec<String>>>()
.register_type::<HashMap<String, HashMap<u32, Vec<String>>>>()
.add_event::<AnimationMarkerReached>()
.register_type::<BlueprintsList>()
.register_type::<MyAsset>()
.register_type::<Vec<MyAsset>>()
.register_type::<Vec<String>>()
.register_type::<LocalAssets>()
.register_type::<AllAssets>()
.register_type::<HashMap<String, Vec<String>>>()
.insert_resource(BluePrintsConfig {
format: self.format,
@ -158,20 +158,23 @@ impl Plugin for BlueprintsPlugin {
Update,
(
test_thingy,
(
check_for_loaded2,
spawn_from_blueprints2,
/*(
prepare_blueprints,
check_for_loaded,
spawn_from_blueprints,
apply_deferred,
)
.chain(),
.chain(),*/
(compute_scene_aabbs, apply_deferred)
.chain()
.run_if(aabbs_enabled),
apply_deferred,
(
materials_inject,
check_for_material_loaded,
// check_for_material_loaded,
materials_inject2,
)
.chain()

View File

@ -66,7 +66,9 @@ pub(crate) fn materials_inject(
} else {
let material_file_handle: Handle<Gltf> = asset_server.load(materials_path.clone());
let material_file_id = material_file_handle.id();
let asset_infos: Vec<AssetLoadTracker<Gltf>> = vec![AssetLoadTracker {
// FIXME: fix this stuff
/*let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
name: material_full_path,
id: material_file_id,
loaded: false,
@ -81,12 +83,14 @@ pub(crate) fn materials_inject(
..Default::default()
})
.insert(BlueprintMaterialAssetsNotLoaded);
/**/
*/
}
}
}
// TODO, merge with check_for_loaded, make generic ?
// FIXME: fix this:
/*
pub(crate) fn check_for_material_loaded(
mut blueprint_assets_to_load: Query<
(Entity, &mut AssetsToLoad<Gltf>),
@ -121,7 +125,7 @@ pub(crate) fn check_for_material_loaded(
}
}
}
*/
/// system that injects / replaces materials from material library
pub(crate) fn materials_inject2(
mut blueprints_config: ResMut<BluePrintsConfig>,

View File

@ -0,0 +1,248 @@
/// helper component, for tracking loaded assets's loading state, id , handle etc
#[derive(Default, Debug)]
pub(crate) struct AssetLoadTracker<T: bevy::prelude::Asset> {
#[allow(dead_code)]
pub name: String,
pub id: AssetId<T>,
pub loaded: bool,
#[allow(dead_code)]
pub handle: Handle<T>,
}
/// helper component, for tracking loaded assets
#[derive(Component, Debug)]
pub(crate) struct AssetsToLoad<T: bevy::prelude::Asset> {
pub all_loaded: bool,
pub asset_infos: Vec<AssetLoadTracker<T>>,
pub progress: f32,
}
impl<T: bevy::prelude::Asset> Default for AssetsToLoad<T> {
fn default() -> Self {
Self {
all_loaded: Default::default(),
asset_infos: Default::default(),
progress: Default::default(),
}
}
}
/// flag component, usually added when a blueprint is loaded
#[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 prepare_blueprints(
spawn_placeholders: Query<
(
Entity,
&BlueprintName,
Option<&Parent>,
Option<&Library>,
Option<&Name>,
Option<&BlueprintsList>,
),
(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![];
let library_path =
library_override.map_or_else(|| &blueprints_config.library_folder, |l| &l.0);
for (blueprint_name, _) in blueprints_list.0.iter() {
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.is_empty() {
commands
.entity(entity)
.insert(AssetsToLoad {
all_loaded: false,
asset_infos,
..Default::default()
})
.insert(BlueprintAssetsNotLoaded);
} else {
commands.entity(entity).insert(BlueprintAssetsLoaded);
}
} else {
// in case there are no blueprintsList, we revert back to the old behaviour
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 game_world: Query<Entity, With<GameWorldTag>>,
assets_gltf: Res<Assets<Gltf>>,
asset_server: Res<AssetServer>,
blueprints_config: Res<BluePrintsConfig>,
children: Query<&Children>,
) {
for (
entity,
blupeprint_name,
transform,
original_parent,
library_override,
add_to_world,
name,
) in spawn_placeholders.iter()
{
debug!(
"attempting to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}",
blupeprint_name.0, name, entity, original_parent
);
let what = &blupeprint_name.0;
let model_file_name = format!("{}.{}", &what, &blueprints_config.format);
// library path is either defined at the plugin level or overriden by optional Library components
let library_path =
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()));
// info!("attempting to spawn {:?}", model_path);
let model_handle: Handle<Gltf> = asset_server.load(model_path.clone()); // FIXME: kinda weird now
let gltf = assets_gltf.get(&model_handle).unwrap_or_else(|| {
panic!(
"gltf file {:?} should have been loaded",
model_path.to_str()
)
});
// WARNING we work under the assumtion that there is ONLY ONE named scene, and that the first one is the right one
let main_scene_name = gltf
.named_scenes
.keys()
.next()
.expect("there should be at least one named scene in the gltf file to spawn");
let scene = &gltf.named_scenes[main_scene_name];
// transforms are optional, but still deal with them correctly
let mut transforms: Transform = Transform::default();
if transform.is_some() {
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((
SceneBundle {
scene: scene.clone(),
transform: transforms,
..Default::default()
},
Spawned,
OriginalChildren(original_children),
BlueprintAnimations {
// these are animations specific to the inside of the blueprint
named_animations: gltf.named_animations.clone(),
},
));
if add_to_world.is_some() {
let world = game_world
.get_single_mut()
.expect("there should be a game world present");
commands.entity(world).add_child(entity);
}
}
}

View File

@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
use bevy::{gltf::Gltf, prelude::*, utils::HashMap};
use crate::{BluePrintsConfig, BlueprintAnimations, BlueprintsList, AssetLoadTracker, AssetsToLoad, BlueprintAssetsNotLoaded, BlueprintAssetsLoaded};
use crate::{AllAssets, AssetsToLoad, AssetLoadTracker, BluePrintsConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded};
/// this is a flag component for our levels/game world
#[derive(Component)]
@ -59,81 +59,103 @@ pub(crate) fn test_thingy(
Entity,
&BlueprintPath,
),
(Added<BlueprintPath>, Without<Spawned>, Without<SpawnHere>),
>,
(Added<BlueprintPath>, Without<Spawned>, Without<SpawnHere>)>,
// before 0.14 we have to use a seperate query, after migrating we can query at the root level
entities_with_assets: Query<
(
Entity,
/*&BlueprintName,
&BlueprintPath,
Option<&Parent>,*/
Option<&Name>,
Option<&AllAssets>,
),
(Added<AllAssets>), // Added<AllAssets>
>,
bla_bla : Query<
(Entity,
&BlueprintName,
&BlueprintPath,
Option<&Parent>,),(Added<BlueprintPath>)
>,
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
for (entity, blueprint_path) in spawn_placeholders.iter() {
println!("added blueprint_path {:?}", blueprint_path);
commands.entity(entity).insert(
//println!("added blueprint_path {:?}", blueprint_path);
/*commands.entity(entity).insert(
SceneBundle {
scene: asset_server.load(format!("{}#Scene0", &blueprint_path.0)), // "levels/World.glb#Scene0"),
..default()
},
);
);*/
// let model_handle: Handle<Gltf> = asset_server.load(model_path.clone());
}
}
for (entity, blueprint_name, blueprint_path, parent) in bla_bla.iter() {
println!("added blueprint to spawn {:?} {:?}", blueprint_name, blueprint_path);
let untyped_handle = asset_server.load_untyped(&blueprint_path.0);
let asset_id = untyped_handle.id();
let loaded = asset_server.is_loaded_with_dependencies(asset_id);
/// spawning prepare function,
/// * also takes into account the already exisiting "override" components, ie "override components" > components from blueprint
pub(crate) fn prepare_blueprints(
spawn_placeholders: Query<
(
Entity,
&BlueprintName,
Option<&Parent>,
Option<&Library>,
Option<&Name>,
Option<&BlueprintsList>,
),
(Added<BlueprintName>, Added<SpawnHere>, Without<Spawned>),
>,
let mut asset_infos: Vec<AssetLoadTracker> = vec![];
if !loaded {
asset_infos.push(AssetLoadTracker {
name: blueprint_name.0.clone(),
id: asset_id,
loaded: false,
handle: untyped_handle.clone(),
});
}
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
);
// now insert load tracker
if !asset_infos.is_empty() {
commands
.entity(entity)
.insert(AssetsToLoad {
all_loaded: false,
asset_infos,
..Default::default()
})
.insert(BlueprintAssetsNotLoaded);
} else {
commands.entity(entity).insert(BlueprintAssetsLoaded);
}
}
// 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![];
let library_path =
library_override.map_or_else(|| &blueprints_config.library_folder, |l| &l.0);
for (blueprint_name, _) in blueprints_list.0.iter() {
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()));
for (child_entity, child_entity_name, all_assets) in entities_with_assets.iter(){
println!("added assets {:?} to {:?}", all_assets, child_entity_name);
if all_assets.is_some() {
let mut asset_infos: Vec<AssetLoadTracker> = vec![];
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);
for asset in all_assets.unwrap().0.iter() {
let untyped_handle = asset_server.load_untyped(&asset.path);
//println!("untyped handle {:?}", untyped_handle);
//asset_server.load(asset.path);
let asset_id = untyped_handle.id();
//println!("ID {:?}", asset_id);
let loaded = asset_server.is_loaded_with_dependencies(asset_id);
//println!("Loaded ? {:?}", loaded);
if !loaded {
asset_infos.push(AssetLoadTracker {
name: model_path.to_string_lossy().into(),
id: model_id,
name: asset.name.clone(),
id: asset_id,
loaded: false,
handle: model_handle.clone(),
handle: untyped_handle.clone(),
});
}
}
// if not all assets are already loaded, inject a component to signal that we need them to be loaded
// now insert load tracker
if !asset_infos.is_empty() {
commands
.entity(entity)
.entity(child_entity)
.insert(AssetsToLoad {
all_loaded: false,
asset_infos,
@ -141,59 +163,66 @@ pub(crate) fn prepare_blueprints(
})
.insert(BlueprintAssetsNotLoaded);
} else {
commands.entity(entity).insert(BlueprintAssetsLoaded);
commands.entity(child_entity).insert(BlueprintAssetsLoaded);
}
} else {
// in case there are no blueprintsList, we revert back to the old behaviour
commands.entity(entity).insert(BlueprintAssetsLoaded);
}
}
}
pub(crate) fn check_for_loaded(
pub(crate) fn check_for_loaded2(
mut blueprint_assets_to_load: Query<
(Entity, &mut AssetsToLoad<Gltf>),
(Entity, Option<&Name>, &mut AssetsToLoad),
With<BlueprintAssetsNotLoaded>,
>,
asset_server: Res<AssetServer>,
mut commands: Commands,
) {
for (entity, mut assets_to_load) in blueprint_assets_to_load.iter_mut() {
for (entity,entity_name, 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 {
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;
tracker.loaded = loaded || failed;
if loaded || failed {
loaded_amount += 1;
} else {
all_loaded = false;
}
}
let progress: f32 = loaded_amount as f32 / total as f32;
// println!("progress: {}",progress);
println!("progress: {}",progress);
assets_to_load.progress = progress;
if all_loaded {
assets_to_load.all_loaded = true;
println!("done with loading {:?}, inserting components", entity_name);
commands
.entity(entity)
.insert(BlueprintAssetsLoaded)
.remove::<BlueprintAssetsNotLoaded>();
.remove::<BlueprintAssetsNotLoaded>()
.remove::<AssetsToLoad>()
;
}
}
}
pub(crate) fn spawn_from_blueprints(
pub(crate) fn spawn_from_blueprints2(
spawn_placeholders: Query<
(
Entity,
&BlueprintName,
&BlueprintPath,
Option<&Transform>,
Option<&Parent>,
Option<&Library>,
Option<&AddToGameWorld>,
Option<&Name>,
),
@ -216,33 +245,28 @@ pub(crate) fn spawn_from_blueprints(
for (
entity,
blupeprint_name,
blueprint_path,
transform,
original_parent,
library_override,
add_to_world,
name,
) in spawn_placeholders.iter()
{
debug!(
"attempting to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}",
info!(
"attempting to spawn blueprint {:?} for entity {:?}, id: {:?}, parent:{:?}",
blupeprint_name.0, name, entity, original_parent
);
let what = &blupeprint_name.0;
let model_file_name = format!("{}.{}", &what, &blueprints_config.format);
// library path is either defined at the plugin level or overriden by optional Library components
let library_path =
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()));
// info!("attempting to spawn {:?}", model_path);
let model_handle: Handle<Gltf> = asset_server.load(model_path.clone()); // FIXME: kinda weird now
let model_handle: Handle<Gltf> = asset_server.load(blueprint_path.0.clone()); // FIXME: kinda weird now
let gltf = assets_gltf.get(&model_handle).unwrap_or_else(|| {
panic!(
"gltf file {:?} should have been loaded",
model_path.to_str()
&blueprint_path.0
)
});
@ -289,3 +313,8 @@ pub(crate) fn spawn_from_blueprints(
}
}
}

View File

@ -95,8 +95,8 @@ pub(crate) fn spawned_blueprint_post_process(
commands.entity(original).remove::<SpawnHere>();
commands.entity(original).remove::<Spawned>();
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(original).remove::<AssetsToLoad>(); // 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();
}
}

View File

@ -0,0 +1 @@
some text

View File

@ -1,5 +1,5 @@
use bevy::prelude::*;
use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, GameWorldTag};
use bevy_gltf_blueprints::{BluePrintBundle, BlueprintName, BlueprintPath, GameWorldTag};
use bevy_gltf_worlflow_examples_common_rapier::{GameState, InAppRunning};
use bevy_rapier3d::prelude::Velocity;
@ -11,7 +11,7 @@ pub fn setup_game(
mut next_game_state: ResMut<NextState<GameState>>,
) {
// here we actually spawn our game world/level
commands.spawn((
/*commands.spawn((
SceneBundle {
scene: asset_server.load("levels/World.glb#Scene0"),
..default()
@ -19,7 +19,16 @@ pub fn setup_game(
bevy::prelude::Name::from("world"),
GameWorldTag,
InAppRunning,
));*/
commands.spawn((
BlueprintName("World".into()),
BlueprintPath("levels/World.glb".into()),
bevy::prelude::Name::from("world"),
GameWorldTag,
InAppRunning,
));
next_game_state.set(GameState::InGame)
}

View File

@ -6,7 +6,7 @@ pub use in_game::*;
use std::{collections::HashMap, fs, time::Duration};
use bevy_gltf_blueprints::{
BlueprintAnimationPlayerLink, BlueprintName, BlueprintsList, GltfBlueprintsSet, SceneAnimations,
AllAssets, BlueprintAnimationPlayerLink, BlueprintName, GltfBlueprintsSet, SceneAnimations
};
use bevy::{
@ -23,7 +23,7 @@ fn start_game(mut next_app_state: ResMut<NextState<AppState>>) {
// if the export from Blender worked correctly, we should have animations (simplified here by using AnimationPlayerLink)
// if the export from Blender worked correctly, we should have an Entity called "Blueprint4_nested" that has a child called "Blueprint3" that has a "BlueprintName" component with value Blueprint3
// if the export from Blender worked correctly, we should have a blueprints_list
// if the export from Blender worked correctly, we should have an assets_list
// if the export from Blender worked correctly, we should have the correct tree of entities
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
@ -36,7 +36,7 @@ fn validate_export(
scene_animations: Query<(Entity, &SceneAnimations)>,
empties_candidates: Query<(Entity, &Name, &GlobalTransform)>,
blueprints_list: Query<(Entity, &BlueprintsList)>,
assets_list: Query<(Entity, &AllAssets)>,
root: Query<(Entity, &Name, &Children), (Without<Parent>, With<Children>)>,
) {
let animations_found =
@ -66,8 +66,8 @@ fn validate_export(
break;
}
}
// check if there are blueprints_list components
let blueprints_list_found = !blueprints_list.is_empty();
// check if there are assets_list components
let assets_list_found = !assets_list.is_empty();
// there should be no entity named xxx____bak as it means an error in the Blender side export process
let mut exported_names_correct = true;
@ -104,8 +104,8 @@ fn validate_export(
fs::write(
"bevy_diagnostics.json",
format!(
"{{ \"animations\": {}, \"nested_blueprint_found\": {}, \"empty_found\": {}, \"blueprints_list_found\": {}, \"exported_names_correct\": {} }}",
animations_found, nested_blueprint_found, empty_found, blueprints_list_found, exported_names_correct
"{{ \"animations\": {}, \"nested_blueprint_found\": {}, \"empty_found\": {}, \"assets_list_found\": {}, \"exported_names_correct\": {} }}",
animations_found, nested_blueprint_found, empty_found, assets_list_found, exported_names_correct
),
)
.expect("Unable to write file");

View File

@ -116,6 +116,8 @@ General issues:
- [ ] remove 'export_marked_assets' it should be a default setting
- [x] disable/ hide asset editing ui for external assets
- [ ] inject_export_path_into_internal_blueprints should be called on every asset/blueprint scan !! Not just on export
- [ ] fix level asets UI
- [x] fix level asets UI
- [x] remove BlueprintsList & replace is with assets list
clear && pytest -svv --blender-template ../../testing/bevy_example/art/testing_library.blend --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration_prepare.py && pytest -svv --blender-executable /home/ckaos/tools/blender/blender-4.1.0-linux-x64/blender tests/test_bevy_integration.py

View File

@ -109,13 +109,6 @@ def duplicate_object(object, parent, combine_mode, destination_collection, bluep
empty_obj["BlueprintPath"] = f'("{blueprint_path}")'
empty_obj['SpawnHere'] = '()'
# we also inject a list of all sub blueprints, so that the bevy side can preload them
children_per_blueprint = {}
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
if blueprint:
children_per_blueprint[blueprint_name] = blueprint.nested_blueprints
empty_obj["BlueprintsList"] = f"({json.dumps(dict(children_per_blueprint))})"
# we copy custom properties over from our original object to our empty
for component_name, component_value in object.items():
if component_name not in custom_properties_to_filter_out and is_component_valid_and_enabled(object, component_name): #copy only valid properties

View File

@ -8,6 +8,12 @@ from blenvy.materials.materials_helpers import get_all_materials
from .generate_temporary_scene_and_export import generate_temporary_scene_and_export
from .export_gltf import (generate_gltf_export_settings)
# material library logic
# To avoid redundant materials (can be very costly, mostly when using high res textures)
# - we explore a gltf file containing all materials from a blend file
# - we add materialInfo component to each object that uses one of the materials, so that "what material is used by which object" is preserved
#
def clear_material_info(collection_names, library_scenes):
for scene in library_scenes:
root_collection = scene.collection

View File

@ -9,7 +9,7 @@ def draw_assets(layout, name, title, asset_registry, target_type, target_name, e
number_of_generated_assets = len(generated_assets)
header, panel = layout.panel(f"assets{name}", default_closed=True)
header.label(text=title + f"({number_of_user_assets + number_of_generated_assets})", icon="ASSET_MANAGER")
header.label(text=title + f"({number_of_user_assets})", icon="ASSET_MANAGER")
blueprint_assets = target_type == 'BLUEPRINT'
@ -42,8 +42,9 @@ def draw_assets(layout, name, title, asset_registry, target_type, target_name, e
if editable:
row = panel.row()
#panel.separator()
print("here", user_assets)
for asset in user_assets:
print("asset", asset)
row = panel.row()
split = row.split(factor=nesting_indent)
col = split.column()

View File

@ -59,7 +59,7 @@ def setup_data(request):
if os.path.exists(screenshot_observed_path):
os.remove(screenshot_observed_path)
request.addfinalizer(finalizer)
#request.addfinalizer(finalizer)
return None
@ -105,7 +105,7 @@ def test_export_complex(setup_data):
blenvy.auto_export.auto_export = True
blenvy.auto_export.export_scene_settings = True
blenvy.auto_export.export_blueprints = True
blenvy.auto_export.export_materials_library = True
blenvy.auto_export.export_materials_library = False # TODO: switch back
bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene
bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene

View File

@ -53,7 +53,7 @@ def test_export_external_blueprints(setup_data):
blenvy.auto_export.auto_export = True
blenvy.auto_export.export_scene_settings = True
blenvy.auto_export.export_blueprints = True
blenvy.auto_export.export_materials_library = True
blenvy.auto_export.export_materials_library = False # TODO switch back
print("SCENES", bpy.data.scenes)
for scene in bpy.data.scenes: