feat(Blenvy:Bevy): experimentation with hot reload: it works !!

* but it is VERY VERY messy right now
 * BlenvyAssets => BlueprintAssets
 * lots of tweaks & experiments & related changes
This commit is contained in:
kaosat.dev 2024-06-25 18:34:26 +02:00
parent 31f6a0f122
commit 959951bca4
14 changed files with 250 additions and 67 deletions

View File

@ -20,7 +20,7 @@ pub struct LocalAssets(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 BlenvyAssets(pub Vec<MyAsset>);
pub struct BlueprintAssets(pub Vec<MyAsset>);

View File

@ -123,7 +123,7 @@ impl Plugin for BlueprintsPlugin {
.register_type::<Vec<MyAsset>>()
.register_type::<Vec<String>>()
.register_type::<LocalAssets>()
.register_type::<BlenvyAssets>()
.register_type::<BlueprintAssets>()
.register_type::<HashMap<String, Vec<String>>>()

View File

@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
use bevy::{gltf::Gltf, prelude::*, utils::hashbrown::HashMap};
use crate::{BlenvyAssets, AssetsToLoad, AssetLoadTracker, BluePrintsConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded};
use crate::{BlueprintAssets, AssetsToLoad, AssetLoadTracker, BluePrintsConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded};
/// this is a flag component for our levels/game world
#[derive(Component)]
@ -76,9 +76,9 @@ pub(crate) fn test_thingy(
&BlueprintPath,
Option<&Parent>,*/
Option<&Name>,
Option<&BlenvyAssets>,
Option<&BlueprintAssets>,
),
(Added<BlenvyAssets>), // Added<BlenvyAssets>
(Added<BlueprintAssets>), // Added<BlueprintAssets>
>,

View File

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

View File

@ -16,7 +16,7 @@ pub struct MyAsset{
/// helper component, is used to store the list of sub blueprints to enable automatic loading of dependend blueprints
#[derive(Component, Reflect, Default, Debug, Deserialize)]
#[reflect(Component)]
pub struct BlenvyAssets {
pub struct BlueprintAssets {
/// only this field should get filled in from the Blender side
pub assets: Vec<MyAsset>,
/// set to default when deserializing
@ -49,13 +49,13 @@ pub(crate) struct BlueprintAssetsNotLoaded;
pub(crate) struct AssetLoadTracker {
#[allow(dead_code)]
pub name: String,
pub path: String,
pub id: AssetId<LoadedUntypedAsset>,
pub loaded: bool,
#[allow(dead_code)]
pub handle: Handle<LoadedUntypedAsset>,
}
/// helper component, for tracking loaded assets
#[derive(Component, Debug)]
pub(crate) struct BlenvyAssetsLoadState {

View File

@ -64,6 +64,7 @@ pub(crate) fn materials_inject(
let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
name: material_info.name.clone(),
path: material_info.path.clone(),
id: material_file_id,
loaded: false,
handle: material_file_handle.clone(),

View File

@ -89,7 +89,7 @@ impl Plugin for BlueprintsPlugin {
.register_type::<MyAsset>()
.register_type::<Vec<MyAsset>>()
.register_type::<Vec<String>>()
.register_type::<BlenvyAssets>()
.register_type::<BlueprintAssets>()
.add_event::<BlueprintEvent>()
@ -143,6 +143,8 @@ impl Plugin for BlueprintsPlugin {
trigger_blueprint_animation_markers_events,
),
)*/
.add_systems(Update, react_to_asset_changes)
;
}
}

View File

@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
use bevy::{gltf::Gltf, prelude::*, utils::hashbrown::HashMap};
use serde_json::Value;
use crate::{BlenvyAssets, AssetsToLoad, AssetLoadTracker, BlenvyConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded};
use crate::{BlueprintAssets, AssetsToLoad, AssetLoadTracker, BlenvyConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded};
/// this is a flag component for our levels/game world
#[derive(Component)]
@ -103,9 +103,9 @@ pub(crate) fn blueprints_prepare_spawn(
&BlueprintPath,
Option<&Parent>,*/
Option<&Name>,
Option<&BlenvyAssets>,
Option<&BlueprintAssets>,
),
(Added<BlenvyAssets>), // Added<BlenvyAssets>
(Added<BlueprintAssets>), // Added<BlueprintAssets>
>,
@ -115,7 +115,7 @@ pub(crate) fn blueprints_prepare_spawn(
&BlueprintName,
&BlueprintPath,
Option<&Parent>,
Option<&BlenvyAssets>,
Option<&BlueprintAssets>,
),(Added<BlueprintPath>)
>,
mut commands: Commands,
@ -150,10 +150,10 @@ asset_server: Res<AssetServer>,
println!("{} / {}", key, value);
}
if lookup.contains_key("BlenvyAssets"){
let assets_raw = &lookup["BlenvyAssets"];
if lookup.contains_key("BlueprintAssets"){
let assets_raw = &lookup["BlueprintAssets"];
println!("ASSETS RAW {}", assets_raw);
let x: BlenvyAssets = ron::from_str(&assets_raw.as_str().unwrap()).unwrap();
let x: BlueprintAssets = ron::from_str(&assets_raw.as_str().unwrap()).unwrap();
println!("YAHA {:?}", x);
}

View File

@ -1,9 +1,9 @@
use std::path::{Path, PathBuf};
use bevy::{gltf::Gltf, prelude::*, utils::hashbrown::HashMap};
use bevy::{asset::LoadedUntypedAsset, gltf::Gltf, prelude::*, scene::SceneInstance, transform::commands, utils::hashbrown::HashMap};
use serde_json::Value;
use crate::{BlenvyAssets, BlenvyAssetsLoadState, AssetLoadTracker, BlenvyConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded};
use crate::{BlueprintAssets, BlenvyAssetsLoadState, AssetLoadTracker, BlenvyConfig, BlueprintAnimations, BlueprintAssetsLoaded, BlueprintAssetsNotLoaded};
/// this is a flag component for our levels/game world
#[derive(Component)]
@ -19,7 +19,6 @@ pub struct BlueprintInfo {
pub path: String,
}
/// flag component needed to signify the intent to spawn a Blueprint
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
@ -94,17 +93,15 @@ pub(crate) fn blueprints_prepare_spawn(
Entity,
&BlueprintInfo,
Option<&Parent>,
Option<&BlenvyAssets>,
),(Added<BlueprintInfo>)
Option<&BlueprintAssets>,
),(Added<SpawnHere>)
>,
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
for (entity, blueprint_info, parent, all_assets) in blueprint_instances_to_spawn.iter() {
println!("Detected blueprint to spawn {:?} {:?}", blueprint_info.name, blueprint_info.path);
println!("Detected blueprint to spawn: {:?} path:{:?}", blueprint_info.name, blueprint_info.path);
println!("all assets {:?}", all_assets);
//////////////
@ -118,6 +115,7 @@ asset_server: Res<AssetServer>,
if !loaded {
asset_infos.push(AssetLoadTracker {
name: blueprint_info.name.clone(),
path: blueprint_info.path.clone(),
id: asset_id,
loaded: false,
handle: untyped_handle.clone(),
@ -135,10 +133,10 @@ asset_server: Res<AssetServer>,
println!("{} / {}", key, value);
}*/
if lookup.contains_key("BlenvyAssets"){
let assets_raw = &lookup["BlenvyAssets"];
if lookup.contains_key("BlueprintAssets"){
let assets_raw = &lookup["BlueprintAssets"];
//println!("ASSETS RAW {}", assets_raw);
let all_assets: BlenvyAssets = ron::from_str(&assets_raw.as_str().unwrap()).unwrap();
let all_assets: BlueprintAssets = ron::from_str(&assets_raw.as_str().unwrap()).unwrap();
println!("all_assets {:?}", all_assets);
for asset in all_assets.assets.iter() {
@ -152,6 +150,7 @@ asset_server: Res<AssetServer>,
if !loaded {
asset_infos.push(AssetLoadTracker {
name: asset.name.clone(),
path: asset.path.clone(),
id: asset_id,
loaded: false,
handle: untyped_handle.clone(),
@ -223,7 +222,7 @@ pub(crate) fn blueprints_check_assets_loading(
.entity(entity)
.insert(BlueprintAssetsLoaded)
.remove::<BlueprintAssetsNotLoaded>()
.remove::<BlenvyAssetsLoadState>()
//.remove::<BlenvyAssetsLoadState>() //REMOVE it in release mode/ when hot reload is off, keep it for dev/hot reload
;
}else {
println!("LOADING: done for ALL assets of {:?} (instance of {}): {} ",entity_name, blueprint_info.path, progress * 100.0);
@ -231,6 +230,142 @@ pub(crate) fn blueprints_check_assets_loading(
}
}
/*
pub(crate) fn hot_reload_asset_check(
mut blueprint_assets: Query<
(Entity, Option<&Name>, &BlueprintInfo, &mut BlenvyAssetsLoadState)>,
asset_server: Res<AssetServer>,
mut commands: Commands,
){
for (entity, entity_name, blueprint_info, mut assets_to_load) in blueprint_assets.iter_mut() {
for tracker in assets_to_load.asset_infos.iter_mut() {
let asset_id = tracker.id;
asset_server.is_changed()
if asset_server.load_state(asset_id) == bevy::asset::LoadState::
match asset_server.load_state(asset_id) {
bevy::asset::LoadState::Failed(_) => {
failed = true
},
_ => {}
}
}
//AssetEvent::Modified`
}
}*/
use bevy::asset::AssetEvent;
pub(crate) fn react_to_asset_changes(
mut gltf_events: EventReader<AssetEvent<Gltf>>,
mut untyped_events: EventReader<AssetEvent<LoadedUntypedAsset>>,
mut blueprint_assets: Query<(Entity, Option<&Name>, &BlueprintInfo, &mut BlenvyAssetsLoadState, Option<&Children>)>,
asset_server: Res<AssetServer>,
mut commands: Commands,
) {
for event in untyped_events.read() {
for (entity, entity_name, blueprint_info, mut assets_to_load, c) in blueprint_assets.iter_mut() {
for tracker in assets_to_load.asset_infos.iter_mut() {
let asset_id = tracker.id;
println!("changed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_modified(asset_id));
}
}
match event {
AssetEvent::Added { id } => {
// React to the image being created
println!("Added untyped {:?}", asset_server.get_path(*id))
}
AssetEvent::LoadedWithDependencies { id } => {
// React to the image being loaded
// after all dependencies
println!("Loaded with deps untyped {:?}", asset_server.get_path(*id))
}
AssetEvent::Modified { id } => {
// React to the image being modified
println!("Modified untyped {:?}", asset_server.get_path(*id))
}
AssetEvent::Removed { id } => {
// React to the image being removed
println!("Removed untyped {:?}", asset_server.get_path(*id))
},
AssetEvent::Unused { id } => {
// React to the last strong handle for the asset being dropped
println!("unused untyped {:?}", asset_server.get_path(*id))
}
}
}
for event in gltf_events.read() {
// LoadedUntypedAsset
/*for (entity, entity_name, blueprint_info, mut assets_to_load) in blueprint_assets.iter_mut() {
for tracker in assets_to_load.asset_infos.iter_mut() {
let asset_id = tracker.id;
if blueprint_info.path.ends_with("glb") || blueprint_info.path.ends_with("gltf") {
// let typed_asset_id = asset_server.get_handle(blueprint_info.path);
let foo: Handle<Gltf> = asset_server.load(blueprint_info.path.clone());
//println!("changed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_modified(foo.id()));
println!("changed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_modified(foo.id()));
println!("added {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_added(foo.id()));
println!("removed {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_removed(foo.id()));
println!("loaded with deps {:?} (blueprint {}) {}", entity_name, blueprint_info.path, event.is_loaded_with_dependencies(foo.id()));
}
}
}*/
match event {
AssetEvent::Added { id } => {
// React to the image being created
println!("Added gltf, path {:?}", asset_server.get_path(*id));
}
AssetEvent::LoadedWithDependencies { id } => {
// React to the image being loaded
// after all dependencies
println!("Loaded gltf with deps{:?}", asset_server.get_path(*id))
}
AssetEvent::Modified { id } => {
// React to the image being modified
println!("Modified gltf {:?}", asset_server.get_path(*id));
for (entity, entity_name, blueprint_info, mut assets_to_load, children) in blueprint_assets.iter_mut() {
for tracker in assets_to_load.asset_infos.iter_mut() {
if tracker.path == asset_server.get_path(*id).unwrap().to_string() {
println!("HOLY MOLY IT DETECTS !!, now respawn {:?}", entity_name);
if children.is_some() {
for child in children.unwrap().iter(){
commands.entity(*child).despawn_recursive();
}
}
commands.entity(entity)
.remove::<BlueprintAssetsLoaded>()
.remove::<SceneInstance>()
.remove::<BlenvyAssetsLoadState>()
.insert(SpawnHere);
break;
}
}
}
}
AssetEvent::Removed { id } => {
// React to the image being removed
println!("Removed gltf {:?}", asset_server.get_path(*id))
},
AssetEvent::Unused { id } => {
// React to the last strong handle for the asset being dropped
println!("unused gltf {:?}", asset_server.get_path(*id))
}
}
}
}
pub(crate) fn blueprints_spawn(

View File

@ -8,7 +8,7 @@ use bevy::scene::SceneInstance;
use crate::{BlueprintAnimationPlayerLink, BlueprintAnimations, BlueprintInfo};
use crate::{SpawnHere, Spawned};
use crate::{
BlenvyAssetsLoadState, BlueprintAssetsLoaded, BlueprintEvent, CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren
BlueprintEvent, CopyComponents, InBlueprint, NoInBlueprint, OriginalChildren
};

View File

@ -153,7 +153,6 @@ fn process_colorgrading(
for entity in cameras.iter(){
for blender_colorgrading in blender_colorgradings.iter(){
println!("COLOR GRADING");
commands.entity(entity).insert(
ColorGrading{
global: ColorGradingGlobal{

View File

@ -13231,21 +13231,36 @@
"type": "object",
"typeInfo": "Struct"
},
"blenvy::blueprints::assets::BlenvyAssets": {
"blenvy::blueprints::assets::BlueprintAssets": {
"additionalProperties": false,
"isComponent": true,
"isResource": false,
"items": false,
"long_name": "blenvy::blueprints::assets::BlenvyAssets",
"prefixItems": [
{
"long_name": "blenvy::blueprints::assets::BlueprintAssets",
"properties": {
"assets": {
"type": {
"$ref": "#/$defs/alloc::vec::Vec<blenvy::blueprints::assets::MyAsset>"
}
},
"loaded": {
"type": {
"$ref": "#/$defs/bool"
}
},
"progress": {
"type": {
"$ref": "#/$defs/f32"
}
}
},
"required": [
"assets",
"loaded",
"progress"
],
"short_name": "BlenvyAssets",
"type": "array",
"typeInfo": "TupleStruct"
"short_name": "BlueprintAssets",
"type": "object",
"typeInfo": "Struct"
},
"blenvy::blueprints::assets::MyAsset": {
"additionalProperties": false,
@ -13297,37 +13312,30 @@
"type": "object",
"typeInfo": "Struct"
},
"blenvy::blueprints::spawn_from_blueprints::BlueprintName": {
"blenvy::blueprints::spawn_from_blueprints::BlueprintInfo": {
"additionalProperties": false,
"isComponent": true,
"isResource": false,
"items": false,
"long_name": "blenvy::blueprints::spawn_from_blueprints::BlueprintName",
"prefixItems": [
{
"long_name": "blenvy::blueprints::spawn_from_blueprints::BlueprintInfo",
"properties": {
"name": {
"type": {
"$ref": "#/$defs/alloc::string::String"
}
},
"path": {
"type": {
"$ref": "#/$defs/alloc::string::String"
}
}
},
"required": [
"name",
"path"
],
"short_name": "BlueprintName",
"type": "array",
"typeInfo": "TupleStruct"
},
"blenvy::blueprints::spawn_from_blueprints::BlueprintPath": {
"isComponent": true,
"isResource": false,
"items": false,
"long_name": "blenvy::blueprints::spawn_from_blueprints::BlueprintPath",
"prefixItems": [
{
"type": {
"$ref": "#/$defs/alloc::string::String"
}
}
],
"short_name": "BlueprintPath",
"type": "array",
"typeInfo": "TupleStruct"
"short_name": "BlueprintInfo",
"type": "object",
"typeInfo": "Struct"
},
"blenvy::blueprints::spawn_from_blueprints::SpawnHere": {
"additionalProperties": false,
@ -13376,6 +13384,31 @@
"type": "object",
"typeInfo": "Struct"
},
"blenvy::components::blender_settings::lighting::BlenderColorGrading": {
"additionalProperties": false,
"isComponent": true,
"isResource": false,
"long_name": "blenvy::components::blender_settings::lighting::BlenderColorGrading",
"properties": {
"exposure": {
"type": {
"$ref": "#/$defs/f32"
}
},
"gamma": {
"type": {
"$ref": "#/$defs/f32"
}
}
},
"required": [
"exposure",
"gamma"
],
"short_name": "BlenderColorGrading",
"type": "object",
"typeInfo": "Struct"
},
"blenvy::components::blender_settings::lighting::BlenderLightShadows": {
"additionalProperties": false,
"isComponent": true,
@ -13420,6 +13453,19 @@
"type": "object",
"typeInfo": "Struct"
},
"blenvy::components::blender_settings::lighting::BlenderToneMapping": {
"isComponent": true,
"isResource": false,
"long_name": "blenvy::components::blender_settings::lighting::BlenderToneMapping",
"oneOf": [
"None",
"AgX",
"Filmic"
],
"short_name": "BlenderToneMapping",
"type": "string",
"typeInfo": "Enum"
},
"bool": {
"isComponent": false,
"isResource": false,

View File

@ -7,7 +7,7 @@ pub use animation::*;
use std::{collections::HashMap, fs, time::Duration};
use blenvy::{
BlenvyAssets, BlueprintAnimationPlayerLink, BlueprintEvent, BlueprintInfo, GltfBlueprintsSet, SceneAnimations
BlueprintAssets, BlueprintAnimationPlayerLink, BlueprintEvent, BlueprintInfo, GltfBlueprintsSet, SceneAnimations
};
use bevy::{
@ -39,7 +39,7 @@ fn validate_export(
scene_animations: Query<(Entity, &SceneAnimations)>,
empties_candidates: Query<(Entity, &Name, &GlobalTransform)>,
assets_list: Query<(Entity, &BlenvyAssets)>,
assets_list: Query<(Entity, &BlueprintAssets)>,
root: Query<(Entity, &Name, &Children), (Without<Parent>, With<Children>)>,
) {
let animations_found =

View File

@ -1,5 +1,5 @@
use bevy::{gltf::{GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras}, prelude::*};
use blenvy::{BlenvyAssets, BlueprintInstanceReady};
use blenvy::{BlueprintAssets, BlueprintInstanceReady};
use crate::BasicTest;
@ -32,7 +32,7 @@ pub fn get_descendants(
all_children: &Query<&Children>,
all_names:&Query<&Name>, root: &Entity,
nesting: usize,
to_check: &Query<&BasicTest>//&Query<(&BlueprintInstanceReady, &BlenvyAssets)>,
to_check: &Query<&BasicTest>//&Query<(&BlueprintInstanceReady, &BlueprintAssets)>,
)
-> String
{
@ -67,7 +67,7 @@ pub fn draw_hierarchy_debug(
all_children: Query<&Children>,
all_names:Query<&Name>,
to_check: Query<&BasicTest>,//Query<(&BlueprintInstanceReady, &BlenvyAssets)>,
to_check: Query<&BasicTest>,//Query<(&BlueprintInstanceReady, &BlueprintAssets)>,
mut display: Query<&mut Text, With<HiearchyDebugTag>>,
){
let mut hierarchy_display: Vec<String> = vec![];