Compare commits

..

1 Commits

Author SHA1 Message Date
Mark Moissette
d86c503e60
Merge e54d41ca5c into 9b50d77790 2024-07-21 00:08:30 +00:00
26 changed files with 192 additions and 286 deletions

18
TODO.md
View File

@ -62,7 +62,7 @@ Components:
- [x] Hashmap Support - [x] Hashmap Support
- [x] fix parsing of keys's type either on Bevy side (prefered) or on the Blender side - [x] fix parsing of keys's type either on Bevy side (prefered) or on the Blender side
- [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set - [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set
- [x] handle missing types in registry for keys & values - [ ] handle missing types in registry for keys & values
- [x] adding a hashmap nukes every existing component ?? - [x] adding a hashmap nukes every existing component ??
- [x] Add correct upgrade handling from individual component to bevy_components - [x] Add correct upgrade handling from individual component to bevy_components
- [x] Settings handling: - [x] Settings handling:
@ -218,12 +218,7 @@ Blender side:
- [ ] add option to 'split out' meshes from blueprints ? - [ ] add option to 'split out' meshes from blueprints ?
- [ ] ie considering meshletts etc , it would make sense to keep blueprints seperate from purely mesh gltfs - [ ] ie considering meshletts etc , it would make sense to keep blueprints seperate from purely mesh gltfs
- [ ] persist exported materials path in blueprints so that it can be read from library file users
- [ ] materials fixes & upgrades
- [x] materials do not get exported again if the files are missing, until you change a material
- [x] materials do not get exported when a material is added ?
- [ ] material assets seem to be added to list regardless of whether material exports are enabled or not
- [ ] persist exported materials path in blueprints so that it can be read from library file users
- [ ] just like "export_path" write it into each blueprint's collection - [ ] just like "export_path" write it into each blueprint's collection
- [ ] scan for used materials per blueprint ! - [ ] scan for used materials per blueprint !
- [ ] for scenes, scan for used materials of all non instance objects (TODO: what about overrides ?) - [ ] for scenes, scan for used materials of all non instance objects (TODO: what about overrides ?)
@ -289,7 +284,7 @@ Bevy Side:
- [x] for sub blueprint tracking: do not propagate/ deal with parent blueprints if they are not themselves Spawning (ie filter out by "BlueprintSpawning") - [x] for sub blueprint tracking: do not propagate/ deal with parent blueprints if they are not themselves Spawning (ie filter out by "BlueprintSpawning")
- [x] cleanup internals - [x] cleanup internals
- [ ] analyse what is off with blueprint level components - [ ] analyse what is off with blueprint level components
- [x] add the root blueprint itself to the assets either on the blender side or on the bevy side programatically - [ ] add the root blueprint itself to the assets either on the blender side or on the bevy side programatically
- [ ] invalidate despawned entity & parent entities AABB - [ ] invalidate despawned entity & parent entities AABB
- [ ] add unloading/cache removal of materials - [ ] add unloading/cache removal of materials
@ -321,11 +316,6 @@ Bevy Side:
- [x] replace all references to the old 2 add-ons with those to Blenvy - [x] replace all references to the old 2 add-ons with those to Blenvy
- [x] rename repo to "Blenvy" - [x] rename repo to "Blenvy"
- [x] do a deprecation release of all bevy_gltf_xxx crates to point at the new Blenvy crate - [x] do a deprecation release of all bevy_gltf_xxx crates to point at the new Blenvy crate
- [ ] consider finding a way of having unique ids for all objects & collections in Blender (not trivial, if not impossible) - [ ] material assets seem to be added to list regardless of whether material exports are enabled or not
this would allow things such as
- [ ] mapping uuids to blueprint paths
- [ ] solving problems with scene renames
- [ ] the ability to map external TEXT files to data in BLender (git-able, hand editable)
- [x] make aabbs calculation non configurable, getting rid of the last setting (for now)
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 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

@ -14,7 +14,7 @@ license = "MIT OR Apache-2.0"
workspace = true workspace = true
[dependencies] [dependencies]
bevy = { version = "0.14", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } #, "file_watcher" bevy = { version = "0.14", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "file_watcher"] }
serde = "1.0.188" serde = "1.0.188"
ron = "0.8.1" ron = "0.8.1"
serde_json = "1.0.108" serde_json = "1.0.108"

View File

@ -37,7 +37,8 @@ pub fn compute_scene_aabbs(
} }
} }
for entity in other_entities.iter() { for entity in other_entities.iter() {
commands.entity(entity).insert(BlueprintReadyForFinalizing); println!("already got AABB");
commands.entity(entity).insert(BlueprintReadyForFinalizing); // FIXME ! Yikes !!
} }
} }

View File

@ -87,14 +87,10 @@ pub struct AnimationMarkerReached {
///////////////////// /////////////////////
/// triggers events when a given animation marker is reached for BLUEPRINT animations /// triggers events when a given animation marker is reached for BLUEPRINT animations
pub fn trigger_blueprint_animation_markers_events( pub fn trigger_blueprint_animation_markers_events(
animation_data: Query<( animation_data: Query<(Entity, &BlueprintAnimationPlayerLink, &BlueprintAnimationInfosLink, &BlueprintAnimations)>,
Entity,
&BlueprintAnimationPlayerLink,
&BlueprintAnimationInfosLink,
&BlueprintAnimations,
)>,
// FIXME: annoying hiearchy issue yet again: the Markers & AnimationInfos are stored INSIDE the blueprint, so we need to access them differently // FIXME: annoying hiearchy issue yet again: the Markers & AnimationInfos are stored INSIDE the blueprint, so we need to access them differently
animation_infos: Query<(&AnimationInfos, &AnimationMarkers)>, animation_infos: Query<(&AnimationInfos, &AnimationMarkers)>,
animation_players: Query<&AnimationPlayer>, animation_players: Query<&AnimationPlayer>,
@ -103,7 +99,9 @@ pub fn trigger_blueprint_animation_markers_events(
animation_clips: Res<Assets<AnimationClip>>, animation_clips: Res<Assets<AnimationClip>>,
) { ) {
for (entity, player_link, infos_link, animations) in animation_data.iter() { for (entity, player_link, infos_link, animations) in animation_data.iter() {
for (animation_name, node_index) in animations.named_indices.iter() { for (animation_name, node_index) in animations.named_indices.iter() {
let animation_player = animation_players.get(player_link.0).unwrap(); let animation_player = animation_players.get(player_link.0).unwrap();
let (animation_infos, animation_markers) = animation_infos.get(infos_link.0).unwrap(); let (animation_infos, animation_markers) = animation_infos.get(infos_link.0).unwrap();
@ -111,24 +109,21 @@ pub fn trigger_blueprint_animation_markers_events(
if let Some(animation) = animation_player.animation(*node_index) { if let Some(animation) = animation_player.animation(*node_index) {
// animation.speed() // animation.speed()
// animation.completions() // animation.completions()
if let Some(animation_clip_handle) = if let Some(animation_clip_handle) = animations.named_animations.get(animation_name) {
animations.named_animations.get(animation_name)
{
if let Some(animation_clip) = animation_clips.get(animation_clip_handle) { if let Some(animation_clip) = animation_clips.get(animation_clip_handle) {
let animation_length_seconds = animation_clip.duration(); let animation_length_seconds = animation_clip.duration();
let animation_length_frames = let animation_length_frames = animation_infos // FIXME: horribly inneficient
animation_infos // FIXME: horribly inneficient
.animations .animations
.iter() .iter()
.find(|anim| &anim.name == animation_name) .find(|anim| &anim.name == animation_name)
.unwrap() .unwrap()
.frames_length; .frames_length;
// TODO: we also need to take playback speed into account // TODO: we also need to take playback speed into account
let time_in_animation = animation.elapsed() let time_in_animation = animation.elapsed()
- (animation.completions() as f32) * animation_length_seconds; - (animation.completions() as f32) * animation_length_seconds;
let frame_seconds = (animation_length_frames let frame_seconds = (animation_length_frames / animation_length_seconds)
/ animation_length_seconds)
* time_in_animation; * time_in_animation;
// println!("frame seconds {}", frame_seconds); // println!("frame seconds {}", frame_seconds);
let frame = frame_seconds.ceil() as u32; // FIXME , bad hack let frame = frame_seconds.ceil() as u32; // FIXME , bad hack
@ -138,10 +133,7 @@ pub fn trigger_blueprint_animation_markers_events(
if matching_animation_marker.contains_key(&frame) { if matching_animation_marker.contains_key(&frame) {
let matching_markers_per_frame = let matching_markers_per_frame =
matching_animation_marker.get(&frame).unwrap(); matching_animation_marker.get(&frame).unwrap();
println!( println!("FOUND A MARKER {:?} at frame {}", matching_markers_per_frame, frame);
"FOUND A MARKER {:?} at frame {}",
matching_markers_per_frame, frame
);
// FIXME: complete hack-ish solution , otherwise this can fire multiple times in a row, depending on animation length , speed , etc // FIXME: complete hack-ish solution , otherwise this can fire multiple times in a row, depending on animation length , speed , etc
let diff = frame as f32 - frame_seconds; let diff = frame as f32 - frame_seconds;
if diff < 0.1 { if diff < 0.1 {
@ -163,6 +155,7 @@ pub fn trigger_blueprint_animation_markers_events(
} }
} }
/// triggers events when a given animation marker is reached for INSTANCE animations /// triggers events when a given animation marker is reached for INSTANCE animations
pub fn trigger_instance_animation_markers_events( pub fn trigger_instance_animation_markers_events(
animation_infos: Query<( animation_infos: Query<(
@ -185,10 +178,9 @@ pub fn trigger_instance_animation_markers_events(
let animation_player = animation_players.get(player_link.0).unwrap(); let animation_player = animation_players.get(player_link.0).unwrap();
if animation_player.animation_is_playing(*node_index) { if animation_player.animation_is_playing(*node_index) {
if let Some(animation) = animation_player.animation(*node_index) { if let Some(animation) = animation_player.animation(*node_index) {
if let Some(animation_clip_handle) = if let Some(animation_clip_handle) = animations.named_animations.get(animation_name) {
animations.named_animations.get(animation_name)
{
if let Some(animation_clip) = animation_clips.get(animation_clip_handle) { if let Some(animation_clip) = animation_clips.get(animation_clip_handle) {
println!("helooo") println!("helooo")
} }
} }

View File

@ -37,6 +37,7 @@ pub struct BlueprintAllAssets {
pub assets: Vec<BlueprintAsset>, pub assets: Vec<BlueprintAsset>,
} }
//////////////////////// ////////////////////////
/// ///
/// flag component, usually added when a blueprint is loaded /// flag component, usually added when a blueprint is loaded

View File

@ -1,23 +1,26 @@
use crate::{ use crate::{BlueprintAssetsLoadState, BlueprintAssetsLoaded, BlueprintInfo, BlueprintInstanceReady, BlueprintSpawning, FromBlueprint, SpawnBlueprint, SubBlueprintsSpawnTracker};
BlueprintAssetsLoadState, BlueprintAssetsLoaded, BlueprintInfo, BlueprintInstanceReady,
BlueprintSpawning, FromBlueprint, SpawnBlueprint, SubBlueprintsSpawnTracker,
};
use bevy::asset::AssetEvent; use bevy::asset::AssetEvent;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::scene::SceneInstance; use bevy::scene::SceneInstance;
use bevy::utils::hashbrown::HashMap; use bevy::utils::hashbrown::HashMap;
/// Resource mapping asset paths (ideally untyped ids, but more complex) to a list of blueprint instance entity ids /// Resource mapping asset paths (ideally untyped ids, but more complex) to a list of blueprint instance entity ids
#[derive(Debug, Clone, Resource, Default)] #[derive(Debug, Clone, Resource, Default)]
pub(crate) struct AssetToBlueprintInstancesMapper { pub(crate) struct AssetToBlueprintInstancesMapper{
// pub(crate) untyped_id_to_blueprint_entity_ids: HashMap<UntypedAssetId, Vec<Entity>> // pub(crate) untyped_id_to_blueprint_entity_ids: HashMap<UntypedAssetId, Vec<Entity>>
pub(crate) untyped_id_to_blueprint_entity_ids: HashMap<String, Vec<Entity>>, pub(crate) untyped_id_to_blueprint_entity_ids: HashMap<String, Vec<Entity>>
} }
pub(crate) fn react_to_asset_changes( pub(crate) fn react_to_asset_changes(
mut gltf_events: EventReader<AssetEvent<Gltf>>, // FIXME: Problem: we need to react to any asset change, not just gltf files ! mut gltf_events: EventReader<AssetEvent<Gltf>>, // FIXME: Problem: we need to react to any asset change, not just gltf files !
// mut untyped_events: EventReader<AssetEvent<LoadedUntypedAsset>>, // mut untyped_events: EventReader<AssetEvent<LoadedUntypedAsset>>,
blueprint_assets: Query<(Entity, Option<&Name>, &BlueprintInfo, Option<&Children>)>, blueprint_assets: Query<(
Entity,
Option<&Name>,
&BlueprintInfo,
Option<&Children>,
)>,
blueprint_children_entities: Query<&FromBlueprint>, //=> can only be used if the entites are tagged blueprint_children_entities: Query<&FromBlueprint>, //=> can only be used if the entites are tagged
assets_to_blueprint_instances: Res<AssetToBlueprintInstancesMapper>, assets_to_blueprint_instances: Res<AssetToBlueprintInstancesMapper>,
all_parents: Query<&Parent>, all_parents: Query<&Parent>,
@ -25,6 +28,7 @@ pub(crate) fn react_to_asset_changes(
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
mut commands: Commands, mut commands: Commands,
) { ) {
let mut respawn_candidates: Vec<&Entity> = vec![]; let mut respawn_candidates: Vec<&Entity> = vec![];
@ -40,19 +44,15 @@ pub(crate) fn react_to_asset_changes(
// let bla = untyped.unwrap().id(); // let bla = untyped.unwrap().id();
// asset_server.get // asset_server.get
// in order to avoid respawn both a parent & a child , which would crash Bevy, we do things in two steps // in order to avoid respawn both a parent & a child , which would crash Bevy, we do things in two steps
if let Some(entities) = assets_to_blueprint_instances if let Some(entities) = assets_to_blueprint_instances.untyped_id_to_blueprint_entity_ids.get(&asset_path.to_string()) {
.untyped_id_to_blueprint_entity_ids
.get(&asset_path.to_string())
{
for entity in entities.iter() { for entity in entities.iter() {
// println!("matching blueprint instance {}", entity); println!("matching blueprint instance {}", entity);
// disregard entities that are already (re) spawning // disregard entities that are already (re) spawning
if !respawn_candidates.contains(&entity) if !respawn_candidates.contains(&entity) && blueprint_assets.get(*entity).is_ok() && spawning_blueprints.get(*entity).is_err()
&& blueprint_assets.get(*entity).is_ok()
&& spawning_blueprints.get(*entity).is_err()
{ {
respawn_candidates.push(entity); respawn_candidates.push(entity);
} }
} }
} }
} }
@ -65,28 +65,26 @@ pub(crate) fn react_to_asset_changes(
// TODO: improve this, very inneficient // TODO: improve this, very inneficient
let mut retained_candidates: Vec<Entity> = vec![]; let mut retained_candidates: Vec<Entity> = vec![];
'outer: for entity in respawn_candidates.iter() { 'outer: for entity in respawn_candidates.iter() {
for parent in all_parents.iter_ancestors(**entity) { for parent in all_parents.iter_ancestors(**entity){
for ent in respawn_candidates.iter() { for ent in respawn_candidates.iter() {
if **ent == parent { if **ent == parent {
if !retained_candidates.contains(&parent) { if ! retained_candidates.contains(&parent) {
retained_candidates.push(parent); retained_candidates.push(parent);
} }
continue 'outer; continue 'outer;
} }
} }
} }
if !retained_candidates.contains(entity) { if ! retained_candidates.contains(entity) {
retained_candidates.push(**entity); retained_candidates.push(**entity);
} }
} }
// println!("respawn candidates {:?}", respawn_candidates); // println!("respawn candidates {:?}", respawn_candidates);
for retained in retained_candidates.iter() { for retained in retained_candidates.iter() {
// println!("retained {}", retained); println!("retained {}", retained);
if let Ok((entity, entity_name, _blueprint_info, children)) = if let Ok((entity, entity_name, _blueprint_info, children)) = blueprint_assets.get(*retained) {
blueprint_assets.get(*retained) println!("HOLY MOLY IT DETECTS !!, now respawn {:?}", entity_name);
{
info!("Change detected !!, now respawn {:?}", entity_name);
// TODO: only remove those that are "in blueprint" // TODO: only remove those that are "in blueprint"
if children.is_some() { if children.is_some() {

View File

@ -53,12 +53,7 @@ pub(crate) fn inject_materials(
material_found = Some(material); material_found = Some(material);
} else { } else {
let model_handle: Handle<Gltf> = asset_server.load(material_info.path.clone()); // FIXME: kinda weird now let model_handle: Handle<Gltf> = asset_server.load(material_info.path.clone()); // FIXME: kinda weird now
let mat_gltf = assets_gltf.get(model_handle.id()).unwrap_or_else(|| { let mat_gltf = assets_gltf.get(model_handle.id()).unwrap_or_else(|| panic!("materials file {} should have been preloaded", material_info.path));
panic!(
"materials file {} should have been preloaded",
material_info.path
)
});
if mat_gltf if mat_gltf
.named_materials .named_materials
.contains_key(&material_info.name as &str) .contains_key(&material_info.name as &str)

View File

@ -50,14 +50,19 @@ impl Default for BluePrintBundle {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
/// Plugin for gltf blueprints /// Plugin for gltf blueprints
pub struct BlueprintsPlugin { pub struct BlueprintsPlugin {
/// Automatically generate aabbs for the blueprints root objects
pub aabbs: bool,
} }
impl Default for BlueprintsPlugin { impl Default for BlueprintsPlugin {
fn default() -> Self { fn default() -> Self {
Self { } Self { aabbs: false }
} }
} }
fn aabbs_enabled(blenvy_config: Res<BlenvyConfig>) -> bool {
blenvy_config.aabbs
}
fn hot_reload(watching_for_changes: Res<WatchingForChanges>) -> bool { fn hot_reload(watching_for_changes: Res<WatchingForChanges>) -> bool {
// println!("hot reload ? {}", watching_for_changes.0); // println!("hot reload ? {}", watching_for_changes.0);
@ -126,7 +131,7 @@ impl Plugin for BlueprintsPlugin {
blueprints_cleanup_spawned_scene, blueprints_cleanup_spawned_scene,
// beyond this point : post processing to finalize blueprint instances // beyond this point : post processing to finalize blueprint instances
inject_materials, inject_materials,
compute_scene_aabbs, compute_scene_aabbs, // .run_if(aabbs_enabled),
blueprints_finalize_instances, blueprints_finalize_instances,
) )
.chain() .chain()

View File

@ -4,10 +4,7 @@ use bevy::{gltf::Gltf, prelude::*, scene::SceneInstance, utils::hashbrown::HashM
use serde_json::Value; use serde_json::Value;
use crate::{ use crate::{
AnimationInfos, AssetLoadTracker, AssetToBlueprintInstancesMapper, BlueprintAnimationInfosLink, AnimationInfos, AssetLoadTracker, AssetToBlueprintInstancesMapper, BlenvyConfig, BlueprintAnimationInfosLink, BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintAssets, BlueprintAssetsLoadState, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded, InstanceAnimationInfosLink, InstanceAnimationPlayerLink, InstanceAnimations, WatchingForChanges
BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintAssets, BlueprintAssetsLoadState,
BlueprintAssetsLoaded, BlueprintAssetsNotLoaded, InstanceAnimationInfosLink,
InstanceAnimationPlayerLink, InstanceAnimations, WatchingForChanges,
}; };
/// this is a flag component for our levels/game world /// this is a flag component for our levels/game world
@ -92,6 +89,7 @@ pub enum BlueprintEvent {
}, },
} }
#[derive(Component, Reflect, Debug, Default)] #[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)] #[reflect(Component)]
/// component gets added when a blueprint starts spawning, removed when spawning is completely done /// component gets added when a blueprint starts spawning, removed when spawning is completely done
@ -99,6 +97,7 @@ pub struct BlueprintSpawning;
use gltf::Gltf as RawGltf; use gltf::Gltf as RawGltf;
/* /*
Overview of the Blueprint Spawning process Overview of the Blueprint Spawning process
- Blueprint Load Assets - Blueprint Load Assets
@ -116,7 +115,10 @@ Overview of the Blueprint Spawning process
*/ */
pub(crate) fn blueprints_prepare_spawn( pub(crate) fn blueprints_prepare_spawn(
blueprint_instances_to_spawn: Query<(Entity, &BlueprintInfo), Added<SpawnBlueprint>>, blueprint_instances_to_spawn: Query<
(Entity, &BlueprintInfo),
Added<SpawnBlueprint>,
>,
mut commands: Commands, mut commands: Commands,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
// for hot reload // for hot reload
@ -151,9 +153,9 @@ pub(crate) fn blueprints_prepare_spawn(
/* prefetch attempt */ /* prefetch attempt */
let gltf = RawGltf::open(format!("assets/{}", blueprint_info.path)).unwrap(); let gltf = RawGltf::open(format!("assets/{}", blueprint_info.path)).unwrap();
for scene in gltf.scenes() { for scene in gltf.scenes() {
if let Some(scene_extras) = scene.extras().clone() { if let Some(scene_extras) = scene.extras().clone()
let lookup: HashMap<String, Value> = {
serde_json::from_str(scene_extras.get()).unwrap(); let lookup: HashMap<String, Value> = serde_json::from_str(scene_extras.get()).unwrap();
if lookup.contains_key("BlueprintAssets") { if lookup.contains_key("BlueprintAssets") {
let assets_raw = &lookup["BlueprintAssets"]; let assets_raw = &lookup["BlueprintAssets"];
//println!("ASSETS RAW {}", assets_raw); //println!("ASSETS RAW {}", assets_raw);
@ -181,56 +183,18 @@ pub(crate) fn blueprints_prepare_spawn(
// Only do this if hot reload is enabled // Only do this if hot reload is enabled
if watching_for_changes.0 { if watching_for_changes.0 {
if !assets_to_blueprint_instances if !assets_to_blueprint_instances.untyped_id_to_blueprint_entity_ids.contains_key(&path_id) {
.untyped_id_to_blueprint_entity_ids assets_to_blueprint_instances.untyped_id_to_blueprint_entity_ids.insert(path_id.clone(), vec![]);
.contains_key(&path_id)
{
assets_to_blueprint_instances
.untyped_id_to_blueprint_entity_ids
.insert(path_id.clone(), vec![]);
} }
// only insert if not already present in mapping // only insert if not already present in mapping
if !assets_to_blueprint_instances.untyped_id_to_blueprint_entity_ids if !assets_to_blueprint_instances.untyped_id_to_blueprint_entity_ids[&path_id].contains(&entity) {
[&path_id]
.contains(&entity)
{
// println!("adding mapping between {} and entity {:?}", path_id, all_names.get(entity)); // println!("adding mapping between {} and entity {:?}", path_id, all_names.get(entity));
assets_to_blueprint_instances assets_to_blueprint_instances.untyped_id_to_blueprint_entity_ids.get_mut(&path_id).unwrap().push(entity);
.untyped_id_to_blueprint_entity_ids
.get_mut(&path_id)
.unwrap()
.push(entity);
}
}
}
}
} }
} }
// Only do this if hot reload is enabled
// TODO: should this be added to the list of "all assets" on the blender side instead
if watching_for_changes.0 {
// also add the root blueprint info to the list of hot reload items
if !assets_to_blueprint_instances
.untyped_id_to_blueprint_entity_ids
.contains_key(&blueprint_info.path)
{
assets_to_blueprint_instances
.untyped_id_to_blueprint_entity_ids
.insert(blueprint_info.path.clone(), vec![]);
} }
// only insert if not already present in mapping }
if !assets_to_blueprint_instances.untyped_id_to_blueprint_entity_ids
[&blueprint_info.path]
.contains(&entity)
{
// println!("adding mapping between {} and entity {:?}", path_id, all_names.get(entity));
assets_to_blueprint_instances
.untyped_id_to_blueprint_entity_ids
.get_mut(&blueprint_info.path)
.unwrap()
.push(entity);
} }
} }
@ -279,9 +243,7 @@ pub(crate) fn blueprints_check_assets_loading(
let loaded = asset_server.is_loaded_with_dependencies(asset_id); let loaded = asset_server.is_loaded_with_dependencies(asset_id);
let mut failed = false; let mut failed = false;
if let bevy::asset::LoadState::Failed(_) = asset_server.load_state(asset_id) { if let bevy::asset::LoadState::Failed(_) = asset_server.load_state(asset_id) { failed = true }
failed = true
}
tracker.loaded = loaded || failed; tracker.loaded = loaded || failed;
if loaded || failed { if loaded || failed {
loaded_amount += 1; loaded_amount += 1;
@ -305,10 +267,12 @@ pub(crate) fn blueprints_check_assets_loading(
commands commands
.entity(entity) .entity(entity)
.insert(BlueprintAssetsLoaded) .insert(BlueprintAssetsLoaded)
.remove::<BlueprintAssetsNotLoaded>(); .remove::<BlueprintAssetsNotLoaded>()
;
if !watching_for_changes.0 { if !watching_for_changes.0 {
commands.entity(entity).remove::<BlueprintAssetsLoadState>(); //we REMOVE this component when in hot reload is OFF, as we commands.entity(entity)
.remove::<BlueprintAssetsLoadState>(); //we REMOVE this component when in hot reload is OFF, as we
} }
} }
} }
@ -592,11 +556,12 @@ pub(crate) fn blueprints_cleanup_spawned_scene(
all_names: Query<&Name>, all_names: Query<&Name>,
) { ) {
for (original, children, original_children, name, animations) in blueprint_scenes.iter() { for (original, children, original_children, name, animations) in
blueprint_scenes.iter()
{
info!("Cleaning up spawned scene {:?}", name); info!("Cleaning up spawned scene {:?}", name);
if children.len() == 0 { if children.len() == 0 { // TODO: investigate, Honestly not sure if this issue from Bevy 0.12 is still present at all anymore
// TODO: investigate, Honestly not sure if this issue from Bevy 0.12 is still present at all anymore
warn!("timing issue ! no children found, please restart your bevy app (bug being investigated)"); warn!("timing issue ! no children found, please restart your bevy app (bug being investigated)");
continue; continue;
} }
@ -617,6 +582,7 @@ pub(crate) fn blueprints_cleanup_spawned_scene(
commands.entity(child).insert(FromBlueprint); // we do this here in order to avoid doing it to normal children commands.entity(child).insert(FromBlueprint); // we do this here in order to avoid doing it to normal children
} }
// copy components into from blueprint instance's blueprint_root_entity to original entity // copy components into from blueprint instance's blueprint_root_entity to original entity
commands.add(CopyComponents { commands.add(CopyComponents {
source: blueprint_root_entity, source: blueprint_root_entity,
@ -666,10 +632,14 @@ pub(crate) fn blueprints_cleanup_spawned_scene(
all_names.get(child), all_names.get(child),
all_names.get(original) all_names.get(original)
); );
commands.entity(original).insert( commands
.entity(original)
.insert(
//BlueprintAnimationPlayerLink(bla), //BlueprintAnimationPlayerLink(bla),
BlueprintAnimationInfosLink(child), BlueprintAnimationInfosLink(child)
); )
;
} else { } else {
for parent in all_parents.iter_ancestors(child) { for parent in all_parents.iter_ancestors(child) {
if animation_players.get(parent).is_ok() { if animation_players.get(parent).is_ok() {
@ -693,9 +663,8 @@ pub(crate) fn blueprints_cleanup_spawned_scene(
)); ));
} }
if with_animation_infos.get(parent).is_ok() { if with_animation_infos.get(parent).is_ok() {
commands commands.entity(child).insert(InstanceAnimationInfosLink(parent));
.entity(child)
.insert(InstanceAnimationInfosLink(parent));
} }
} }
} }

View File

@ -65,6 +65,7 @@ fn components_string_to_components(
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap(); ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
println!("serialized Component {}", serialized); println!("serialized Component {}", serialized);
*/ */
debug!("component data ron string {}", ron_string); debug!("component data ron string {}", ron_string);
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()) let mut deserializer = ron::Deserializer::from_str(ron_string.as_str())
.expect("deserialzer should have been generated from string"); .expect("deserialzer should have been generated from string");

View File

@ -13,13 +13,13 @@ pub use blueprints::*;
#[derive(Clone, Resource)] #[derive(Clone, Resource)]
pub struct BlenvyConfig { pub struct BlenvyConfig {
// registry // registry
pub(crate) export_registry: bool,
pub(crate) registry_save_path: PathBuf, pub(crate) registry_save_path: PathBuf,
pub(crate) registry_component_filter: SceneFilter, pub(crate) registry_component_filter: SceneFilter,
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) registry_resource_filter: SceneFilter, pub(crate) registry_resource_filter: SceneFilter,
// blueprints // blueprints
pub(crate) aabbs: bool,
pub(crate) aabb_cache: HashMap<String, Aabb>, // cache for aabbs pub(crate) aabb_cache: HashMap<String, Aabb>, // cache for aabbs
pub(crate) materials_cache: HashMap<String, Handle<StandardMaterial>>, // cache for materials pub(crate) materials_cache: HashMap<String, Handle<StandardMaterial>>, // cache for materials
@ -31,12 +31,14 @@ pub struct BlenvyConfig {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
/// Plugin for gltf blueprints /// Plugin for gltf blueprints
pub struct BlenvyPlugin { pub struct BlenvyPlugin {
pub export_registry: bool,
pub registry_save_path: PathBuf, pub registry_save_path: PathBuf,
pub registry_component_filter: SceneFilter, pub registry_component_filter: SceneFilter,
pub registry_resource_filter: SceneFilter, pub registry_resource_filter: SceneFilter,
/// Automatically generate aabbs for the blueprints root objects
pub aabbs: bool,
// for save & load // for save & load
pub save_component_filter: SceneFilter, pub save_component_filter: SceneFilter,
pub save_resource_filter: SceneFilter, pub save_resource_filter: SceneFilter,
@ -45,10 +47,10 @@ pub struct BlenvyPlugin {
impl Default for BlenvyPlugin { impl Default for BlenvyPlugin {
fn default() -> Self { fn default() -> Self {
Self { Self {
export_registry: true,
registry_save_path: PathBuf::from("registry.json"), // relative to assets folder registry_save_path: PathBuf::from("registry.json"), // relative to assets folder
registry_component_filter: SceneFilter::default(), registry_component_filter: SceneFilter::default(),
registry_resource_filter: SceneFilter::default(), registry_resource_filter: SceneFilter::default(),
aabbs: false,
save_component_filter: SceneFilter::default(), save_component_filter: SceneFilter::default(),
save_resource_filter: SceneFilter::default(), save_resource_filter: SceneFilter::default(),
@ -64,17 +66,17 @@ impl Plugin for BlenvyPlugin {
BlueprintsPlugin::default(), BlueprintsPlugin::default(),
)) ))
.insert_resource(BlenvyConfig { .insert_resource(BlenvyConfig {
export_registry: self.export_registry,
registry_save_path: self.registry_save_path.clone(), registry_save_path: self.registry_save_path.clone(),
registry_component_filter: self.registry_component_filter.clone(), registry_component_filter: self.registry_component_filter.clone(),
registry_resource_filter: self.registry_resource_filter.clone(), registry_resource_filter: self.registry_resource_filter.clone(),
aabbs: self.aabbs,
aabb_cache: HashMap::new(), aabb_cache: HashMap::new(),
materials_cache: HashMap::new(), materials_cache: HashMap::new(),
save_component_filter: self.save_component_filter.clone(), save_component_filter: self.save_component_filter.clone(),
save_resource_filter: self.save_resource_filter.clone(), save_resource_filter: self.save_resource_filter.clone()
}); });
} }
} }

View File

@ -6,12 +6,10 @@ pub use export_types::*;
use bevy::{ use bevy::{
app::Startup, app::Startup,
asset::AssetPlugin, asset::AssetPlugin,
prelude::{App, IntoSystemConfigs, Plugin, Res, Resource}, prelude::{App, Plugin, Resource},
scene::SceneFilter, scene::SceneFilter,
}; };
use crate::BlenvyConfig;
pub struct ExportRegistryPlugin { pub struct ExportRegistryPlugin {
pub component_filter: SceneFilter, pub component_filter: SceneFilter,
pub resource_filter: SceneFilter, pub resource_filter: SceneFilter,
@ -28,14 +26,9 @@ impl Default for ExportRegistryPlugin {
} }
} }
fn export_registry(blenvy_config: Res<BlenvyConfig>) -> bool {
// TODO: add detection of Release builds, wasm, and android in order to avoid exporting registry in those cases
blenvy_config.export_registry
}
impl Plugin for ExportRegistryPlugin { impl Plugin for ExportRegistryPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_asset_root().add_systems(Startup, export_types.run_if(export_registry)); app.register_asset_root().add_systems(Startup, export_types);
} }
} }

View File

@ -1,11 +1,7 @@
use std::time::Duration; use std::time::Duration;
use bevy::prelude::*; use bevy::prelude::*;
use blenvy::{ use blenvy::{AddToGameWorld, BlenvyPlugin, BluePrintBundle, BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintInfo, DynamicBlueprintInstance, GameWorldTag, HideUntilReady, SpawnBlueprint};
AddToGameWorld, BlenvyPlugin, BluePrintBundle, BlueprintAnimationPlayerLink,
BlueprintAnimations, BlueprintInfo, DynamicBlueprintInstance, GameWorldTag, HideUntilReady,
SpawnBlueprint,
};
use rand::Rng; use rand::Rng;
mod component_examples; mod component_examples;
@ -26,24 +22,31 @@ pub struct Fox;
/// Demo marker component /// Demo marker component
pub struct Robot; pub struct Robot;
fn main() { fn main() {
App::new() App::new()
.add_plugins(( .add_plugins((
DefaultPlugins.set(AssetPlugin::default()), DefaultPlugins.set(AssetPlugin::default()),
// our custom plugins // our custom plugins
ComponentsExamplesPlugin, // Showcases different type of components /structs ComponentsExamplesPlugin, // Showcases different type of components /structs
BlenvyPlugin::default(), BlenvyPlugin::default()
)) ))
.register_type::<Player>() .register_type::<Player>()
.register_type::<Fox>() .register_type::<Fox>()
.register_type::<Robot>() .register_type::<Robot>()
.add_systems(Startup, setup_game) .add_systems(Startup, setup_game)
.add_systems(Update, (animation_control,)) .add_systems(Update,
(animation_control,)
)
.run(); .run();
} }
// this is how you setup & spawn a level from a blueprint // this is how you setup & spawn a level from a blueprint
fn setup_game(mut commands: Commands) { fn setup_game(
mut commands: Commands,
) {
// here we actually spawn our game world/level // here we actually spawn our game world/level
commands.spawn(( commands.spawn((
BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info... BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info...
@ -53,6 +56,7 @@ fn setup_game(mut commands: Commands) {
)); ));
} }
////////////////////////////////// //////////////////////////////////
pub fn animation_control( pub fn animation_control(

View File

@ -1,8 +1,5 @@
use bevy::prelude::*; use bevy::prelude::*;
use blenvy::{ use blenvy::{AddToGameWorld, BlenvyPlugin, BluePrintBundle, BlueprintInfo, DynamicBlueprintInstance, GameWorldTag, HideUntilReady, SpawnBlueprint};
AddToGameWorld, BlenvyPlugin, BluePrintBundle, BlueprintInfo, DynamicBlueprintInstance,
GameWorldTag, HideUntilReady, SpawnBlueprint,
};
use rand::Rng; use rand::Rng;
mod component_examples; mod component_examples;
@ -14,15 +11,20 @@ fn main() {
DefaultPlugins.set(AssetPlugin::default()), DefaultPlugins.set(AssetPlugin::default()),
// our custom plugins // our custom plugins
ComponentsExamplesPlugin, // Showcases different type of components /structs ComponentsExamplesPlugin, // Showcases different type of components /structs
BlenvyPlugin::default(), BlenvyPlugin::default()
)) ))
.add_systems(Startup, setup_game) .add_systems(Startup, setup_game)
.add_systems(Update, spawn_blueprint_instance) .add_systems(Update, spawn_blueprint_instance)
.run(); .run();
} }
// this is how you setup & spawn a level from a blueprint // this is how you setup & spawn a level from a blueprint
fn setup_game(mut commands: Commands) { fn setup_game(
mut commands: Commands,
) {
// here we spawn our game world/level, which is also a blueprint ! // here we spawn our game world/level, which is also a blueprint !
commands.spawn(( commands.spawn((
BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info... BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info...
@ -32,6 +34,7 @@ fn setup_game(mut commands: Commands) {
)); ));
} }
// you can also spawn blueprint instances at runtime // you can also spawn blueprint instances at runtime
pub fn spawn_blueprint_instance( pub fn spawn_blueprint_instance(
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
@ -64,8 +67,10 @@ pub fn spawn_blueprint_instance(
HideUntilReady, HideUntilReady,
AddToGameWorld, AddToGameWorld,
TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)), TransformBundle::from_transform(Transform::from_xyz(x, 2.0, y)),
)) ))
.id(); .id();
// commands.entity(world).add_child(new_entity); // commands.entity(world).add_child(new_entity);
} }
} }

View File

@ -10,13 +10,18 @@ fn main() {
DefaultPlugins.set(AssetPlugin::default()), DefaultPlugins.set(AssetPlugin::default()),
// our custom plugins // our custom plugins
ComponentsExamplesPlugin, // Showcases different type of components /structs ComponentsExamplesPlugin, // Showcases different type of components /structs
BlenvyPlugin::default(), BlenvyPlugin::default()
)) ))
.add_systems(Startup, setup_game) .add_systems(Startup, setup_game)
.run(); .run();
} }
fn setup_game(mut commands: Commands) {
fn setup_game(
mut commands: Commands,
) {
// here we actually spawn our game world/level // here we actually spawn our game world/level
commands.spawn(( commands.spawn((
BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info... BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info...

View File

@ -1,6 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_gltf_worlflow_examples_common_rapier::{assets::GameAssets, GameState, InAppRunning};
use blenvy::{BluePrintBundle, BlueprintName, GameWorldTag}; use blenvy::{BluePrintBundle, BlueprintName, GameWorldTag};
use bevy_gltf_worlflow_examples_common_rapier::{assets::GameAssets, GameState, InAppRunning};
use bevy_rapier3d::prelude::Velocity; use bevy_rapier3d::prelude::Velocity;
use rand::Rng; use rand::Rng;

View File

@ -1,9 +1,9 @@
use bevy::{gltf::Gltf, prelude::*}; use bevy::{gltf::Gltf, prelude::*};
use blenvy::GameWorldTag;
use bevy_gltf_worlflow_examples_common_rapier::{ use bevy_gltf_worlflow_examples_common_rapier::{
assets::GameAssets, GameState, InAppRunning, Player, assets::GameAssets, GameState, InAppRunning, Player,
}; };
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
use blenvy::GameWorldTag;
#[derive(Component, Reflect, Default, Debug)] #[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)] #[reflect(Component)]

View File

@ -12,9 +12,7 @@ from .export_gltf import get_standard_exporter_settings
from ..levels.export_levels import export_level_scene from ..levels.export_levels import export_level_scene
from ..blueprints.export_blueprints import export_blueprints from ..blueprints.export_blueprints import export_blueprints
from .export_materials import cleanup_materials, export_materials
from ..materials.get_materials_to_export import get_materials_to_export
from ..materials.export_materials import cleanup_materials, export_materials
from ..levels.bevy_scene_components import remove_scene_components, upsert_scene_components from ..levels.bevy_scene_components import remove_scene_components, upsert_scene_components
@ -72,7 +70,9 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
# since materials export adds components we need to call this before blueprints are exported # since materials export adds components we need to call this before blueprints are exported
# export materials & inject materials components into relevant objects # export materials & inject materials components into relevant objects
materials_to_export = get_materials_to_export(changes_per_material, changed_export_parameters, blueprints_data, settings) # FIXME: improve change detection, perhaps even add "material changes"
if export_materials_library and (changed_export_parameters or len(changes_per_material.keys()) > 0 ):
export_materials(blueprints_data.blueprint_names, settings.library_scenes, settings)
# update the list of tracked exports # update the list of tracked exports
exports_total = len(blueprints_to_export) + len(level_scenes_to_export) + (1 if export_materials_library else 0) exports_total = len(blueprints_to_export) + len(level_scenes_to_export) + (1 if export_materials_library else 0)
@ -92,9 +92,7 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
print("-------------------------------") print("-------------------------------")
print("BLUEPRINTS: to export:", [blueprint.name for blueprint in blueprints_to_export]) print("BLUEPRINTS: to export:", [blueprint.name for blueprint in blueprints_to_export])
print("-------------------------------") print("-------------------------------")
print("LEVELS: to export:", level_scenes_to_export) print("MAIN SCENES: to export:", level_scenes_to_export)
print("-------------------------------")
print("MATERIALS: to export:", materials_to_export)
print("-------------------------------") print("-------------------------------")
# backup current active scene # backup current active scene
old_current_scene = bpy.context.scene old_current_scene = bpy.context.scene
@ -114,10 +112,6 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
print("export LIBRARY") print("export LIBRARY")
export_blueprints(blueprints_to_export, settings, blueprints_data) export_blueprints(blueprints_to_export, settings, blueprints_data)
# then deal with materials
if export_materials_library:
export_materials(materials_to_export, settings, blueprints_data)#blueprints_data.blueprint_names, settings.library_scenes, settings)
# reset current scene from backup # reset current scene from backup
bpy.context.window.scene = old_current_scene bpy.context.window.scene = old_current_scene

View File

@ -5,8 +5,8 @@ from pathlib import Path
from blenvy.core.helpers_collections import (traverse_tree) from blenvy.core.helpers_collections import (traverse_tree)
from blenvy.core.object_makers import make_cube from blenvy.core.object_makers import make_cube
from blenvy.materials.materials_helpers import add_material_info_to_objects, get_all_materials from blenvy.materials.materials_helpers import add_material_info_to_objects, get_all_materials
from ..common.generate_temporary_scene_and_export import generate_temporary_scene_and_export from .generate_temporary_scene_and_export import generate_temporary_scene_and_export
from ..common.export_gltf import (generate_gltf_export_settings) from .export_gltf import (generate_gltf_export_settings)
# material library logic # material library logic
# To avoid redundant materials (can be very costly, mostly when using high res textures) # To avoid redundant materials (can be very costly, mostly when using high res textures)
@ -65,12 +65,11 @@ def clear_materials_scene(temp_scene):
# exports the materials used inside the current project: # exports the materials used inside the current project:
# the name of the output path is <materials_folder>/<name_of_your_blend_file>_materials_library.gltf/glb # the name of the output path is <materials_folder>/<name_of_your_blend_file>_materials_library.gltf/glb
def export_materials(materials_to_export, settings, blueprints_data): def export_materials(collections, library_scenes, settings):
if len(materials_to_export) > 0:
gltf_export_settings = generate_gltf_export_settings(settings) gltf_export_settings = generate_gltf_export_settings(settings)
materials_path_full = getattr(settings,"materials_path_full") materials_path_full = getattr(settings,"materials_path_full")
(used_material_names, materials_per_object) = get_all_materials(blueprints_data.blueprint_names, settings.library_scenes) (used_material_names, materials_per_object) = get_all_materials(collections, library_scenes)
add_material_info_to_objects(materials_per_object, settings) add_material_info_to_objects(materials_per_object, settings)
gltf_export_settings = { **gltf_export_settings, gltf_export_settings = { **gltf_export_settings,
@ -97,8 +96,6 @@ def export_materials(materials_to_export, settings, blueprints_data):
) )
def cleanup_materials(collections, library_scenes): def cleanup_materials(collections, library_scenes):
# remove temporary components # remove temporary components
clear_material_info(collections, library_scenes) clear_material_info(collections, library_scenes)

View File

@ -1,31 +0,0 @@
import bpy
from blenvy.materials.materials_helpers import find_materials_not_on_disk
def get_materials_to_export(changes_per_material, changed_export_parameters, blueprints_data, settings):
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
blueprints_path_full = getattr(settings,"blueprints_path_full", "")
materials_path_full = getattr(settings,"materials_path_full", "")
change_detection = getattr(settings.auto_export, "change_detection")
collection_instances_combine_mode = getattr(settings.auto_export, "collection_instances_combine_mode")
all_materials = bpy.data.materials
local_materials = [material for material in all_materials if material.library is None]
#and (changed_export_parameters or len(changes_per_material.keys()) > 0 )
materials_to_export = []
if change_detection and not changed_export_parameters:
changed_materials = []
# first check if all materials have already been exported before (if this is the first time the exporter is run
# in your current Blender session for example)
materials_not_on_disk = find_materials_not_on_disk(local_materials, materials_path_full, export_gltf_extension)
# also deal with blueprints that are always marked as "always_export"
#materials_always_export = [material for material in internal_materials if is_material_always_export(material)]
materials_always_export = []
materials_to_export = list(set(changed_materials + materials_not_on_disk + materials_always_export))
return materials_to_export

View File

@ -1,5 +1,5 @@
import posixpath
import bpy import bpy
import os
from pathlib import Path from pathlib import Path
from blenvy.assets.assets_scan import get_blueprint_asset_tree, get_level_scene_assets_tree2 from blenvy.assets.assets_scan import get_blueprint_asset_tree, get_level_scene_assets_tree2
@ -10,6 +10,9 @@ def assets_to_fake_ron(list_like):
return f"(assets: {result})".replace("'", '') return f"(assets: {result})".replace("'", '')
return f"({result})".replace("'", '')
# TODO : move to assets # TODO : move to assets
def upsert_scene_assets(scene, blueprints_data, settings): def upsert_scene_assets(scene, blueprints_data, settings):
"""print("level scene", scene) """print("level scene", scene)
@ -30,7 +33,7 @@ def upsert_scene_assets(scene, blueprints_data, settings):
blueprints_path = getattr(settings, "blueprints_path") blueprints_path = getattr(settings, "blueprints_path")
for blueprint in blueprints_in_scene: for blueprint in blueprints_in_scene:
if blueprint.local: if blueprint.local:
blueprint_exported_path = posixpath.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}") blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}")
else: else:
# get the injected path of the external blueprints # get the injected path of the external blueprints
blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None
@ -53,7 +56,7 @@ def upsert_scene_assets(scene, blueprints_data, settings):
materials_path = getattr(settings, "materials_path") materials_path = getattr(settings, "materials_path")
current_project_name = Path(bpy.context.blend_data.filepath).stem current_project_name = Path(bpy.context.blend_data.filepath).stem
materials_library_name = f"{current_project_name}_materials" materials_library_name = f"{current_project_name}_materials"
materials_exported_path = posixpath.join(materials_path, f"{materials_library_name}{export_gltf_extension}") materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}")
material_assets = [{"name": materials_library_name, "path": materials_exported_path}] # we also add the material library as an asset material_assets = [{"name": materials_library_name, "path": materials_exported_path}] # we also add the material library as an asset
print("material_assets", material_assets, "extension", export_gltf_extension) print("material_assets", material_assets, "extension", export_gltf_extension)

View File

@ -1,6 +1,5 @@
import os import os
import json import json
import posixpath
import bpy import bpy
from .asset_helpers import does_asset_exist, get_user_assets, get_user_assets_as_list from .asset_helpers import does_asset_exist, get_user_assets, get_user_assets_as_list
@ -23,7 +22,7 @@ def scan_assets(scene, blueprints_data, settings):
#print("BLUEPRINT", blueprint) #print("BLUEPRINT", blueprint)
blueprint_exported_path = None blueprint_exported_path = None
if blueprint.local: if blueprint.local:
blueprint_exported_path = posixpath.join(relative_blueprints_path, f"{blueprint.name}{export_gltf_extension}") blueprint_exported_path = os.path.join(relative_blueprints_path, f"{blueprint.name}{export_gltf_extension}")
else: else:
# get the injected path of the external blueprints # get the injected path of the external blueprints
blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None
@ -72,7 +71,7 @@ def get_blueprint_assets_tree(blueprint, blueprints_data, parent, settings):
if child_blueprint: if child_blueprint:
blueprint_exported_path = None blueprint_exported_path = None
if blueprint.local: if blueprint.local:
blueprint_exported_path = posixpath.join(blueprints_path, f"{child_blueprint.name}{export_gltf_extension}") blueprint_exported_path = os.path.join(blueprints_path, f"{child_blueprint.name}{export_gltf_extension}")
else: else:
# get the injected path of the external blueprints # get the injected path of the external blueprints
blueprint_exported_path = child_blueprint.collection['export_path'] if 'export_path' in child_blueprint.collection else None blueprint_exported_path = child_blueprint.collection['export_path'] if 'export_path' in child_blueprint.collection else None
@ -102,7 +101,7 @@ def get_level_scene_assets_tree(level_scene, blueprints_data, settings):
if blueprint is not None: if blueprint is not None:
blueprint_exported_path = None blueprint_exported_path = None
if blueprint.local: if blueprint.local:
blueprint_exported_path = posixpath.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}") blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}")
else: else:
# get the injected path of the external blueprints # get the injected path of the external blueprints
blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None
@ -135,7 +134,7 @@ def get_level_scene_assets_tree2(level_scene, blueprints_data, settings):
if blueprint is not None: if blueprint is not None:
blueprint_exported_path = None blueprint_exported_path = None
if blueprint.local: if blueprint.local:
blueprint_exported_path = posixpath.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}") blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}")
else: else:
# get the injected path of the external blueprints # get the injected path of the external blueprints
blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None blueprint_exported_path = blueprint.collection['export_path'] if 'export_path' in blueprint.collection else None
@ -157,7 +156,7 @@ def get_blueprint_asset_tree(blueprint, blueprints_data, settings):
if sub_blueprint is not None: if sub_blueprint is not None:
sub_blueprint_exported_path = None sub_blueprint_exported_path = None
if sub_blueprint.local: if sub_blueprint.local:
sub_blueprint_exported_path = posixpath.join(blueprints_path, f"{sub_blueprint.name}{export_gltf_extension}") sub_blueprint_exported_path = os.path.join(blueprints_path, f"{sub_blueprint.name}{export_gltf_extension}")
else: else:
# get the injected path of the external blueprints # get the injected path of the external blueprints
sub_blueprint_exported_path = sub_blueprint.collection['export_path'] if 'export_path' in sub_blueprint.collection else None sub_blueprint_exported_path = sub_blueprint.collection['export_path'] if 'export_path' in sub_blueprint.collection else None

View File

@ -3,7 +3,6 @@ import os
import json import json
import bpy import bpy
from pathlib import Path from pathlib import Path
import posixpath
from ..core.scene_helpers import add_scene_property from ..core.scene_helpers import add_scene_property
@ -29,10 +28,10 @@ def inject_export_path_into_internal_blueprints(internal_blueprints, blueprints_
materials_path = getattr(settings, "materials_path") materials_path = getattr(settings, "materials_path")
current_project_name = Path(bpy.context.blend_data.filepath).stem current_project_name = Path(bpy.context.blend_data.filepath).stem
materials_library_name = f"{current_project_name}_materials" materials_library_name = f"{current_project_name}_materials"
materials_exported_path = posixpath.join(materials_path, f"{materials_library_name}{export_gltf_extension}") materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}")
for blueprint in internal_blueprints: for blueprint in internal_blueprints:
blueprint_exported_path = posixpath.join(blueprints_path, f"{blueprint.name}{gltf_extension}") blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{gltf_extension}")
# print("injecting blueprint path", blueprint_exported_path, "for", blueprint.name) # print("injecting blueprint path", blueprint_exported_path, "for", blueprint.name)
blueprint.collection["export_path"] = blueprint_exported_path blueprint.collection["export_path"] = blueprint_exported_path
if export_materials_library: if export_materials_library:
@ -59,7 +58,7 @@ def inject_blueprints_list_into_level_scene(scene, blueprints_data, settings):
#print("BLUEPRINT", blueprint) #print("BLUEPRINT", blueprint)
blueprint_exported_path = None blueprint_exported_path = None
if blueprint.local: if blueprint.local:
blueprint_exported_path = posixpath.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}") blueprint_exported_path = os.path.join(blueprints_path, f"{blueprint.name}{export_gltf_extension}")
else: else:
# get the injected path of the external blueprints # get the injected path of the external blueprints
blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None

View File

@ -1,24 +1,8 @@
import os import os
import posixpath
import bpy import bpy
from pathlib import Path from pathlib import Path
from ..core.helpers_collections import (traverse_tree) from ..core.helpers_collections import (traverse_tree)
def find_materials_not_on_disk(materials, folder_path, extension):
not_found_materials = []
for material in materials:
gltf_output_path = os.path.join(folder_path, material.name + extension)
# print("gltf_output_path", gltf_output_path)
found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path)
if not found:
not_found_materials.append(material)
return not_found_materials
def check_if_material_on_disk(scene_name, folder_path, extension):
gltf_output_path = os.path.join(folder_path, scene_name + extension)
found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path)
return found
# get materials per object, and injects the materialInfo component # get materials per object, and injects the materialInfo component
def get_materials(object, materials_per_object): def get_materials(object, materials_per_object):
material_slots = object.material_slots material_slots = object.material_slots
@ -54,11 +38,11 @@ def add_material_info_to_objects(materials_per_object, settings):
current_project_name = Path(bpy.context.blend_data.filepath).stem current_project_name = Path(bpy.context.blend_data.filepath).stem
materials_library_name = f"{current_project_name}_materials" materials_library_name = f"{current_project_name}_materials"
materials_exported_path = posixpath.join(materials_path, f"{materials_library_name}{export_gltf_extension}") materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}")
for object in materials_per_object.keys(): for object in materials_per_object.keys():
material = materials_per_object[object] material = materials_per_object[object]
# TODO: switch to using actual components ? # TODO: switch to using actual components ?
materials_exported_path = posixpath.join(materials_path, f"{materials_library_name}{export_gltf_extension}") materials_exported_path = os.path.join(materials_path, f"{materials_library_name}{export_gltf_extension}")
object['MaterialInfo'] = f'(name: "{material.name}", path: "{materials_exported_path}")' object['MaterialInfo'] = f'(name: "{material.name}", path: "{materials_exported_path}")'