From a618e0035ec28af575a4d23c3f99b44bf41b9a7c Mon Sep 17 00:00:00 2001 From: "kaosat.dev" Date: Thu, 18 Jul 2024 13:42:29 +0200 Subject: [PATCH] chore(crates): updated code from main to v0.14 compatibility for all old crates --- crates/bevy_gltf_blueprints/Cargo.toml | 4 +- crates/bevy_gltf_blueprints/README.md | 56 +++- crates/bevy_gltf_blueprints/src/animation.rs | 213 +------------- .../src/copy_components.rs | 3 +- crates/bevy_gltf_blueprints/src/lib.rs | 148 +++++----- crates/bevy_gltf_blueprints/src/materials.rs | 50 ++-- .../src/spawn_from_blueprints.rs | 265 +++++++++--------- .../src/spawn_post_process.rs | 17 +- crates/bevy_gltf_components/Cargo.toml | 4 +- crates/bevy_gltf_components/README.md | 88 +----- crates/bevy_gltf_components/src/lib.rs | 34 ++- .../bevy_gltf_components/src/process_gltfs.rs | 126 +++------ .../src/ronstring_to_reflect_component.rs | 176 ++++++------ crates/bevy_gltf_save_load/Cargo.toml | 6 +- crates/bevy_gltf_save_load/README.md | 12 +- crates/bevy_registry_export/Cargo.toml | 12 +- crates/bevy_registry_export/README.md | 16 +- .../bevy_registry_export/src/export_types.rs | 45 ++- crates/bevy_registry_export/src/lib.rs | 8 +- crates/blenvy/README.md | 4 +- .../src/blueprints/spawn_from_blueprints.rs | 6 +- 21 files changed, 510 insertions(+), 783 deletions(-) diff --git a/crates/bevy_gltf_blueprints/Cargo.toml b/crates/bevy_gltf_blueprints/Cargo.toml index 2933a84..5ca181c 100644 --- a/crates/bevy_gltf_blueprints/Cargo.toml +++ b/crates/bevy_gltf_blueprints/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [dependencies] bevy_gltf_components = { version = "0.6", path = "../bevy_gltf_components" } -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] } +bevy = { version = "0.14", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf", "bevy_animation", "animation"] } [dev-dependencies] -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file +bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/bevy_gltf_blueprints/README.md b/crates/bevy_gltf_blueprints/README.md index 39a8c71..49cb3b0 100644 --- a/crates/bevy_gltf_blueprints/README.md +++ b/crates/bevy_gltf_blueprints/README.md @@ -3,7 +3,9 @@ [![License](https://img.shields.io/crates/l/bevy_gltf_blueprints)](https://github.com/kaosat-dev/Blender_bevy_components_workflow/blob/main/crates/bevy_gltf_blueprints/License.md) [![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking) -# bevy_gltf_blueprints +# bevy_gltf_blueprints (deprecated in favor of Blenvy) + +> bevy_gltf_blueprints has been deprecated in favor of its successor [Blenvy](https://crates.io/crates/blenvy), part of the [Blenvy project](https://github.com/kaosat-dev/Blenvy). No further development or maintenance will be done for Bevy bevy_gltf_blueprints. See [#194](https://github.com/kaosat-dev/Blenvy/issues/194) for background. Built on [bevy_gltf_components](https://crates.io/crates/bevy_gltf_components) this crate adds the ability to define Blueprints/Prefabs for [Bevy](https://bevyengine.org/) inside gltf files and spawn them in Bevy. @@ -15,8 +17,9 @@ A blueprint is a set of **overrideable** components + a hierarchy: ie * just a Gltf file with Gltf_extras specifying components * a component called BlueprintName -Particularly useful when using [Blender](https://www.blender.org/) as an editor for the [Bevy](https://bevyengine.org/) game engine, combined with the Blender add-on that do a lot of the work for you -- [blenvy](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/blenvy) +Particularly useful when using [Blender](https://www.blender.org/) as an editor for the [Bevy](https://bevyengine.org/) game engine, combined with the Blender add-ons that do a lot of the work for you +- [gltf_auto_export](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/gltf_auto_export) +- [bevy_components](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/bevy_components) ## Usage @@ -26,8 +29,8 @@ Here's a minimal usage example: ```toml # Cargo.toml [dependencies] -bevy="0.13" -bevy_gltf_blueprints = { version = "0.10"} +bevy="0.14" +bevy_gltf_blueprints = { version = "0.11.0"} ``` @@ -65,7 +68,7 @@ fn spawn_blueprint( Add the following to your `[dependencies]` section in `Cargo.toml`: ```toml -bevy_gltf_blueprints = "0.10" +bevy_gltf_blueprints = "0.11.0" ``` Or use `cargo add`: @@ -100,8 +103,11 @@ fn main() { App::new() .add_plugins(( BlueprintsPlugin{ + library_folder: "advanced/models/library".into() // replace this with your blueprints library path , relative to the assets folder, + format: GltfFormat::GLB,// optional, use either format: GltfFormat::GLB, or format: GltfFormat::GLTF, or ..Default::default() if you want to keep the default .glb extension, this sets what extensions/ gltf files will be looked for by the library aabbs: true, // defaults to false, enable this to automatically calculate aabb for the scene/blueprint material_library: true, // defaults to false, enable this to enable automatic injection of materials from material library files + material_library_folder: "materials".into() //defaults to "materials" the folder to look for for the material files ..Default::default() } )) @@ -220,7 +226,7 @@ Typically , the order of systems should be ***bevy_gltf_components (GltfComponentsSet::Injection)*** => ***bevy_gltf_blueprints (GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn)*** => ***replace_proxies*** -see https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/basic for how to set it up correctly +see an example [here](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/basic) for how to set it up correctly @@ -274,9 +280,9 @@ pub fn animation_change_on_proximity_foxes( } ``` -see https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/animation for how to set it up correctly +see [here](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/animation) for how to set it up correctly -particularly from https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/animation/game/in_game.rs +particularly from [here](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/animation/src/game/in_game.rs) ## Materials @@ -290,28 +296,47 @@ Ie for example without this option, 56 different blueprints using the same mater you can configure this with the settings: ```rust material_library: true // defaults to false, enable this to enable automatic injection of materials from material library files +material_library_folder: "materials".into() //defaults to "materials" the folder to look for for the material files ``` > Important! you must take care of preloading your material librairy gltf files in advance, using for example ```bevy_asset_loader```since ```bevy_gltf_blueprints``` currently does NOT take care of loading those at runtime -see https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/materials for how to set it up correctly +see an example [here](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/materials) for how to set it up correctly Generating optimised blueprints and material libraries can be automated using the latests version of the [Blender plugin](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/gltf_auto_export) +## Legacy mode + +Starting in version 0.7 there is a new parameter ```legacy_mode``` for backwards compatibility + +To disable the legacy mode: (enabled by default) + +```rust no_run +BlueprintsPlugin{legacy_mode: false} +``` + + +You **need** to disable legacy mode if you want to use the [```bevy_components```](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/tools_bevy_blueprints/tools/bevy_components) Blender addon + the [```bevy_registry_export crate```](https://crates.io/crates/bevy_registry_export) ! +As it create custom properties that are writen in real **ron** file format instead of a simplified version (the one in the legacy mode) + + +> Note: the legacy mode support will be dropped in future versions, and the default behaviour will be NO legacy mode + + ## Examples -https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/basic +* [basic](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/basic) -https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/basic_xpbd_physics +* [xbpd](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/basic_xpbd_physics) -https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/animation +* [animation](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/animation) -https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/materials +* [materials](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/materials) -https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles +* [multiple_levels_multiple_blendfiles](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_gltf_blueprints/multiple_levels_multiple_blendfiles) ## Compatible Bevy versions @@ -321,6 +346,7 @@ The main branch is compatible with the latest Bevy release, while the branch `be Compatibility of `bevy_gltf_blueprints` versions: | `bevy_gltf_blueprints` | `bevy` | | :-- | :-- | +| `0.11` | `0.14` | | `0.9 - 0.10` | `0.13` | | `0.3 - 0.8` | `0.12` | | `0.1 - 0.2` | `0.11` | diff --git a/crates/bevy_gltf_blueprints/src/animation.rs b/crates/bevy_gltf_blueprints/src/animation.rs index 6792080..4f2d652 100644 --- a/crates/bevy_gltf_blueprints/src/animation.rs +++ b/crates/bevy_gltf_blueprints/src/animation.rs @@ -3,9 +3,11 @@ use bevy::utils::HashMap; #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] -/// storage for animations for a given entity's BLUEPRINT (ie for example a characters animations), essentially a clone of gltf's `named_animations` -pub struct BlueprintAnimations { +/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations` +pub struct Animations { pub named_animations: HashMap>, + pub named_indices: HashMap, + pub graph: Handle, } #[derive(Component, Debug)] @@ -13,209 +15,4 @@ pub struct BlueprintAnimations { /// so that the root entity knows which of its children contains an actualy `AnimationPlayer` component /// this is for convenience, because currently , Bevy's gltf parsing inserts `AnimationPlayers` "one level down" /// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid -pub struct BlueprintAnimationPlayerLink(pub Entity); - -#[derive(Component, Reflect, Default, Debug)] -#[reflect(Component)] -/// storage for scene level animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations` -pub struct SceneAnimations { - pub named_animations: HashMap>, -} - -#[derive(Component, Debug)] -/// Stop gap helper component : this is inserted into a "root" entity (an entity representing a whole gltf file) -/// so that the root entity knows which of its children contains an actualy `AnimationPlayer` component -/// this is for convenience, because currently , Bevy's gltf parsing inserts `AnimationPlayers` "one level down" -/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid -pub struct SceneAnimationPlayerLink(pub Entity); - -/// Stores Animation information: name, frame informations etc -#[derive(Reflect, Default, Debug)] -pub struct AnimationInfo { - pub name: String, - pub frame_start: f32, - pub frame_end: f32, - pub frames_length: f32, - pub frame_start_override: f32, - pub frame_end_override: f32, -} - -/// Stores information about animations, to make things a bit easier api wise: -/// these components are automatically inserted by `gltf_auto_export` on entities that have animations -#[derive(Component, Reflect, Default, Debug)] -#[reflect(Component)] -pub struct AnimationInfos { - pub animations: Vec, -} - -#[derive(Reflect, Default, Debug)] -pub struct AnimationMarker { - // pub frame: u32, - pub name: String, - pub handled_for_cycle: bool, -} - -/// Stores information about animation markers: practical for adding things like triggering events at specific keyframes etc -/// it is essentiall a hashmap of `AnimationName` => `HashMap`<`FrameNumber`, Vec of marker names> -#[derive(Component, Reflect, Default, Debug)] -#[reflect(Component)] -pub struct AnimationMarkers(pub HashMap>>); - -/// Event that gets triggered once a specific marker inside an animation has been reached (frame based) -/// Provides some usefull information about which entity , wich animation, wich frame & which marker got triggered -#[derive(Event, Debug)] -pub struct AnimationMarkerReached { - pub entity: Entity, - pub animation_name: String, - pub frame: u32, - pub marker_name: String, -} - -///////////////////// - -/* -/// triggers events when a given animation marker is reached for INSTANCE animations -pub fn trigger_instance_animation_markers_events( - animation_infos: Query<( - Entity, - &AnimationMarkers, - &SceneAnimationPlayerLink, - &SceneAnimations, - &AnimationInfos, - )>, - animation_players: Query<(&AnimationPlayer)>, - animation_clips: Res>, - animation_graphs: Res>, - mut animation_marker_events: EventWriter, -) { - for (entity, markers, link, animations, animation_infos) in animation_infos.iter() { - let animation_player = animation_players.get(link.0).unwrap(); - let animation_clip = animation_clips.get(animation_player.animation_clip()); - // animation_player.play(animation) - - if animation_clip.is_some() { - // println!("Entity {:?} markers {:?}", entity, markers); - // println!("Player {:?} {}", animation_player.elapsed(), animation_player.completions()); - // FIMXE: yikes ! very inneficient ! perhaps add boilerplate to the "start playing animation" code so we know what is playing - let animation_name = animations.named_animations.iter().find_map(|(key, value)| { - if value == animation_player.animation_clip() { - Some(key) - } else { - None - } - }); - if animation_name.is_some() { - let animation_name = animation_name.unwrap(); - - let animation_length_seconds = animation_clip.unwrap().duration(); - let animation_length_frames = animation_infos - .animations - .iter() - .find(|anim| &anim.name == animation_name) - .unwrap() - .frames_length; - // TODO: we also need to take playback speed into account - let time_in_animation = animation_player.elapsed() - - (animation_player.completions() as f32) * animation_length_seconds; - let frame_seconds = - (animation_length_frames / animation_length_seconds) * time_in_animation; - let frame = frame_seconds as u32; - - let matching_animation_marker = &markers.0[animation_name]; - if matching_animation_marker.contains_key(&frame) { - let matching_markers_per_frame = matching_animation_marker.get(&frame).unwrap(); - - // let timediff = animation_length_seconds - time_in_animation; - // println!("timediff {}", timediff); - // println!("FOUND A MARKER {:?} at frame {}", matching_markers_per_frame, frame); - // emit an event AnimationMarkerReached(entity, animation_name, frame, marker_name) - // FIXME: problem, this can fire multiple times in a row, depending on animation length , speed , etc - for marker in matching_markers_per_frame { - animation_marker_events.send(AnimationMarkerReached { - entity, - animation_name: animation_name.clone(), - frame, - marker_name: marker.clone(), - }); - } - } - } - } - } -} - -/// triggers events when a given animation marker is reached for BLUEPRINT animations -pub fn trigger_blueprint_animation_markers_events( - animation_infos: Query<(Entity, &BlueprintAnimationPlayerLink, &BlueprintAnimations)>, - // FIXME: annoying hiearchy issue yet again: the Markers & AnimationInfos are stored INSIDE the blueprint, so we need to access them differently - all_animation_infos: Query<(Entity, &AnimationMarkers, &AnimationInfos, &Parent)>, - animation_players: Query<&AnimationPlayer>, - animation_clips: Res>, - mut animation_marker_events: EventWriter, -) { - for (entity, link, animations) in animation_infos.iter() { - let animation_player = animation_players.get(link.0).unwrap(); - let animation_clip = animation_clips.get(animation_player.animation_clip()); - - // FIXME: horrible code - for (_, markers, animation_infos, parent) in all_animation_infos.iter() { - if parent.get() == entity { - if animation_clip.is_some() { - // println!("Entity {:?} markers {:?}", entity, markers); - // println!("Player {:?} {}", animation_player.elapsed(), animation_player.completions()); - // FIMXE: yikes ! very inneficient ! perhaps add boilerplate to the "start playing animation" code so we know what is playing - let animation_name = - animations.named_animations.iter().find_map(|(key, value)| { - if value == animation_player.animation_clip() { - Some(key) - } else { - None - } - }); - if animation_name.is_some() { - let animation_name = animation_name.unwrap(); - let animation_length_seconds = animation_clip.unwrap().duration(); - let animation_length_frames = animation_infos - .animations - .iter() - .find(|anim| &anim.name == animation_name) - .unwrap() - .frames_length; - // TODO: we also need to take playback speed into account - let time_in_animation = animation_player.elapsed() - - (animation_player.completions() as f32) * animation_length_seconds; - let frame_seconds = (animation_length_frames / animation_length_seconds) - * time_in_animation; - // println!("frame seconds {}", frame_seconds); - let frame = frame_seconds.ceil() as u32; // FIXME , bad hack - - let matching_animation_marker = &markers.0[animation_name]; - - if matching_animation_marker.contains_key(&frame) { - let matching_markers_per_frame = - matching_animation_marker.get(&frame).unwrap(); - // println!("FOUND A MARKER {:?} at frame {}", matching_markers_per_frame, frame); - // emit an event AnimationMarkerReached(entity, animation_name, frame, marker_name) - // 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; - println!("diff {}", diff); - if diff < 0.1 { - for marker in matching_markers_per_frame { - animation_marker_events.send(AnimationMarkerReached { - entity, - animation_name: animation_name.clone(), - frame, - marker_name: marker.clone(), - }); - } - } - } - } - } - - break; - } - } - } -} -*/ +pub struct AnimationPlayerLink(pub Entity); diff --git a/crates/bevy_gltf_blueprints/src/copy_components.rs b/crates/bevy_gltf_blueprints/src/copy_components.rs index b2a12b5..f978382 100644 --- a/crates/bevy_gltf_blueprints/src/copy_components.rs +++ b/crates/bevy_gltf_blueprints/src/copy_components.rs @@ -1,5 +1,4 @@ -use bevy::ecs::world::Command; -use bevy::prelude::*; +use bevy::{ecs::world::Command, prelude::*}; use std::any::TypeId; // originally based https://github.com/bevyengine/bevy/issues/1515, diff --git a/crates/bevy_gltf_blueprints/src/lib.rs b/crates/bevy_gltf_blueprints/src/lib.rs index 3effb39..36ac25b 100644 --- a/crates/bevy_gltf_blueprints/src/lib.rs +++ b/crates/bevy_gltf_blueprints/src/lib.rs @@ -10,9 +10,6 @@ pub use animation::*; pub mod aabb; pub use aabb::*; -pub mod assets; -pub use assets::*; - pub mod materials; pub use materials::*; @@ -22,7 +19,11 @@ pub use copy_components::*; use core::fmt; use std::path::PathBuf; -use bevy::{prelude::*, render::primitives::Aabb, utils::HashMap}; +use bevy::{ + prelude::*, + render::{primitives::Aabb, view::VisibilitySystems}, + utils::HashMap, +}; use bevy_gltf_components::{ComponentsFromGltfPlugin, GltfComponentsSet}; #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)] @@ -35,14 +36,12 @@ pub enum GltfBlueprintsSet { #[derive(Bundle)] pub struct BluePrintBundle { pub blueprint: BlueprintName, - pub blueprint_path: BlueprintPath, pub spawn_here: SpawnHere, } impl Default for BluePrintBundle { fn default() -> Self { BluePrintBundle { blueprint: BlueprintName("default".into()), - blueprint_path: BlueprintPath("".into()), spawn_here: SpawnHere, } } @@ -50,10 +49,13 @@ impl Default for BluePrintBundle { #[derive(Clone, Resource)] pub struct BluePrintsConfig { + pub(crate) format: GltfFormat, + pub(crate) library_folder: PathBuf, pub(crate) aabbs: bool, pub(crate) aabb_cache: HashMap, // cache for aabbs pub(crate) material_library: bool, + pub(crate) material_library_folder: PathBuf, pub(crate) material_library_cache: HashMap>, } @@ -80,17 +82,27 @@ impl fmt::Display for GltfFormat { #[derive(Debug, Clone)] /// Plugin for gltf blueprints pub struct BlueprintsPlugin { + pub legacy_mode: bool, // flag that gets passed on to bevy_gltf_components + + pub format: GltfFormat, + /// The base folder where library/blueprints assets are loaded from, relative to the executable. + pub library_folder: PathBuf, /// Automatically generate aabbs for the blueprints root objects pub aabbs: bool, /// pub material_library: bool, + pub material_library_folder: PathBuf, } impl Default for BlueprintsPlugin { fn default() -> Self { Self { + legacy_mode: true, + format: GltfFormat::GLB, + library_folder: PathBuf::from("models/library"), aabbs: false, material_library: false, + material_library_folder: PathBuf::from("materials"), } } } @@ -105,84 +117,64 @@ fn materials_library_enabled(blueprints_config: Res) -> bool { impl Plugin for BlueprintsPlugin { fn build(&self, app: &mut App) { - app.add_plugins(ComponentsFromGltfPlugin {}) - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::>() - .register_type::() - .register_type::>>() - .register_type::>>>() - .add_event::() - .register_type::() - .register_type::>() - .register_type::>() - .register_type::() - .register_type::() + app.add_plugins(ComponentsFromGltfPlugin { + legacy_mode: self.legacy_mode, + }) + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::>() + .register_type::>>() + .insert_resource(BluePrintsConfig { + format: self.format, + library_folder: self.library_folder.clone(), + aabbs: self.aabbs, + aabb_cache: HashMap::new(), - .register_type::>>() - .insert_resource(BluePrintsConfig { - - aabbs: self.aabbs, - aabb_cache: HashMap::new(), - - material_library: self.material_library, - material_library_cache: HashMap::new(), - }) - .configure_sets( - Update, - (GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn) - .chain() - .after(GltfComponentsSet::Injection), - ) - .add_systems( - Update, + material_library: self.material_library, + material_library_folder: self.material_library_folder.clone(), + material_library_cache: HashMap::new(), + }) + .configure_sets( + Update, + (GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn) + .chain() + .after(GltfComponentsSet::Injection), + ) + .add_systems( + Update, + ( ( - test_thingy, - check_for_loaded2, - spawn_from_blueprints2, - - /*( - prepare_blueprints, - check_for_loaded, - spawn_from_blueprints, - apply_deferred, - ) - .chain(),*/ - (compute_scene_aabbs, apply_deferred) - .chain() - .run_if(aabbs_enabled), + prepare_blueprints, + check_for_loaded, + spawn_from_blueprints, apply_deferred, - ( - materials_inject, - check_for_material_loaded, - materials_inject2, - ) - .chain() - .run_if(materials_library_enabled), + ) + .chain(), + (compute_scene_aabbs, apply_deferred) + .chain() + .run_if(aabbs_enabled), + apply_deferred, + ( + materials_inject, + check_for_material_loaded, + materials_inject2, ) .chain() - .in_set(GltfBlueprintsSet::Spawn), + .run_if(materials_library_enabled), ) - .add_systems( - Update, - (spawned_blueprint_post_process, apply_deferred) - .chain() - .in_set(GltfBlueprintsSet::AfterSpawn), - ) - /* .add_systems( - Update, - ( - trigger_instance_animation_markers_events, - trigger_blueprint_animation_markers_events, - ), - )*/ - ; + .chain() + .in_set(GltfBlueprintsSet::Spawn), + ) + .add_systems( + PostUpdate, + (spawned_blueprint_post_process, apply_deferred) + .chain() + .in_set(GltfBlueprintsSet::AfterSpawn) + .before(VisibilitySystems::CheckVisibility), + ); } } diff --git a/crates/bevy_gltf_blueprints/src/materials.rs b/crates/bevy_gltf_blueprints/src/materials.rs index 53a95c0..f942331 100644 --- a/crates/bevy_gltf_blueprints/src/materials.rs +++ b/crates/bevy_gltf_blueprints/src/materials.rs @@ -17,14 +17,14 @@ use bevy::{ render::mesh::Mesh, }; -use crate::{AssetLoadTracker, AssetsToLoad, BluePrintsConfig, BlueprintInstanceReady}; +use crate::{AssetLoadTracker, AssetsToLoad, BluePrintsConfig}; #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] -/// struct containing the name & path of the material to apply +/// struct containing the name & source of the material to apply pub struct MaterialInfo { pub name: String, - pub path: String, + pub source: String, } /// flag component @@ -42,8 +42,15 @@ pub(crate) fn materials_inject( mut commands: Commands, ) { for (entity, material_info) in material_infos.iter() { - println!("Entity with material info {:?} {:?}", entity, material_info); - let material_full_path = format!("{}#{}", material_info.path, material_info.name); + let model_file_name = format!( + "{}_materials_library.{}", + &material_info.source, &blueprints_config.format + ); + let materials_path = Path::new(&blueprints_config.material_library_folder) + .join(Path::new(model_file_name.as_str())); + let material_name = &material_info.name; + let material_full_path = materials_path.to_str().unwrap().to_string() + "#" + material_name; // TODO: yikes, cleanup + if blueprints_config .material_library_cache .contains_key(&material_full_path) @@ -57,11 +64,10 @@ pub(crate) fn materials_inject( .entity(entity) .insert(BlueprintMaterialAssetsLoaded); } else { - let material_file_handle = asset_server.load_untyped(&material_info.path.clone()); // : Handle + let material_file_handle: Handle = asset_server.load(materials_path.clone()); let material_file_id = material_file_handle.id(); - - let asset_infos: Vec = vec![AssetLoadTracker { - name: material_info.name.clone(), + let asset_infos: Vec> = vec![AssetLoadTracker { + name: material_full_path, id: material_file_id, loaded: false, handle: material_file_handle.clone(), @@ -75,6 +81,7 @@ pub(crate) fn materials_inject( ..Default::default() }) .insert(BlueprintMaterialAssetsNotLoaded); + /**/ } } } @@ -82,7 +89,7 @@ pub(crate) fn materials_inject( // TODO, merge with check_for_loaded, make generic ? pub(crate) fn check_for_material_loaded( mut blueprint_assets_to_load: Query< - (Entity, &mut AssetsToLoad), + (Entity, &mut AssetsToLoad), With, >, asset_server: Res, @@ -139,7 +146,15 @@ pub(crate) fn materials_inject2( mut commands: Commands, ) { for (material_info, children) in material_infos.iter() { - let material_full_path = format!("{}#{}", material_info.path, material_info.name); + let model_file_name = format!( + "{}_materials_library.{}", + &material_info.source, &blueprints_config.format + ); + let materials_path = Path::new(&blueprints_config.material_library_folder) + .join(Path::new(model_file_name.as_str())); + let material_name = &material_info.name; + + let material_full_path = materials_path.to_str().unwrap().to_string() + "#" + material_name; // TODO: yikes, cleanup let mut material_found: Option<&Handle> = None; if blueprints_config @@ -153,17 +168,14 @@ pub(crate) fn materials_inject2( .expect("we should have the material available"); material_found = Some(material); } else { - let model_handle: Handle = asset_server.load(material_info.path.clone()); // FIXME: kinda weird now + let model_handle: Handle = asset_server.load(materials_path.clone()); // FIXME: kinda weird now let mat_gltf = assets_gltf .get(model_handle.id()) .expect("material should have been preloaded"); - if mat_gltf - .named_materials - .contains_key(&material_info.name as &str) - { + if mat_gltf.named_materials.contains_key(material_name as &str) { let material = mat_gltf .named_materials - .get(&material_info.name as &str) + .get(material_name as &str) .expect("this material should have been loaded"); blueprints_config .material_library_cache @@ -177,8 +189,8 @@ pub(crate) fn materials_inject2( if with_materials_and_meshes.contains(*child) { debug!( "injecting material {}, path: {:?}", - material_info.name, - material_info.path.clone() + material_name, + materials_path.clone() ); commands.entity(*child).insert(material.clone()); diff --git a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs index 29657cc..ea8a02c 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_from_blueprints.rs @@ -1,11 +1,8 @@ use std::path::{Path, PathBuf}; -use bevy::{gltf::Gltf, prelude::*, utils::hashbrown::HashMap}; +use bevy::{gltf::Gltf, prelude::*, utils::HashMap}; -use crate::{ - AssetLoadTracker, AssetsToLoad, BluePrintsConfig, BlueprintAnimations, BlueprintAssets, - BlueprintAssetsLoaded, BlueprintAssetsNotLoaded, -}; +use crate::{Animations, BluePrintsConfig}; /// this is a flag component for our levels/game world #[derive(Component)] @@ -16,11 +13,6 @@ pub struct GameWorldTag; #[reflect(Component)] pub struct BlueprintName(pub String); -/// path component for the blueprints -#[derive(Component, Reflect, Default, Debug)] -#[reflect(Component)] -pub struct BlueprintPath(pub String); - /// flag component needed to signify the intent to spawn a Blueprint #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] @@ -30,12 +22,6 @@ pub struct SpawnHere; /// flag component for dynamically spawned scenes pub struct Spawned; -#[derive(Component, Debug)] -/// flag component added when a Blueprint instance ist Ready : ie : -/// - its assets have loaded -/// - it has finished spawning -pub struct BlueprintInstanceReady; - #[derive(Component, Reflect, Default, Debug)] #[reflect(Component)] /// flag component marking any spwaned child of blueprints ..unless the original entity was marked with the `NoInBlueprint` marker component @@ -60,105 +46,100 @@ pub struct AddToGameWorld; /// helper component, just to transfer child data pub(crate) struct OriginalChildren(pub Vec); -pub(crate) fn test_thingy( - spawn_placeholders: Query< - (Entity, &BlueprintPath), - (Added, Without, Without), - >, +/// 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>); - // before 0.14 we have to use a seperate query, after migrating we can query at the root level - entities_with_assets: Query< +/// helper component, for tracking loaded assets's loading state, id , handle etc +#[derive(Default, Debug)] +pub(crate) struct AssetLoadTracker { + #[allow(dead_code)] + pub name: String, + pub id: AssetId, + pub loaded: bool, + #[allow(dead_code)] + pub handle: Handle, +} + +/// helper component, for tracking loaded assets +#[derive(Component, Debug)] +pub(crate) struct AssetsToLoad { + pub all_loaded: bool, + pub asset_infos: Vec>, + pub progress: f32, +} +impl Default for AssetsToLoad { + 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, - &BlueprintPath, - Option<&Parent>,*/ + &BlueprintName, + Option<&Parent>, + Option<&Library>, Option<&Name>, - Option<&BlueprintAssets>, + Option<&BlueprintsList>, ), - (Added), // Added + (Added, Added, Without), >, - bla_bla: Query< - (Entity, &BlueprintName, &BlueprintPath, Option<&Parent>), - (Added), - >, mut commands: Commands, asset_server: Res, + blueprints_config: Res, ) { - for (entity, blueprint_path) in spawn_placeholders.iter() { - //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 = 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 + 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 ); - 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); - let mut asset_infos: Vec = vec![]; - if !loaded { - asset_infos.push(AssetLoadTracker { - name: blueprint_name.0.clone(), - id: asset_id, - loaded: false, - handle: untyped_handle.clone(), - }); - } + // 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> = 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())); - // 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); - } - } - - 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 = vec![]; - - 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); + let model_handle: Handle = 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: asset.name.clone(), - id: asset_id, + name: model_path.to_string_lossy().into(), + id: model_id, loaded: false, - handle: untyped_handle.clone(), + handle: model_handle.clone(), }); } } - - // now insert load tracker + // 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(child_entity) + .entity(entity) .insert(AssetsToLoad { all_loaded: false, asset_infos, @@ -166,70 +147,59 @@ pub(crate) fn test_thingy( }) .insert(BlueprintAssetsNotLoaded); } else { - commands.entity(child_entity).insert(BlueprintAssetsLoaded); + 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_loaded2( +pub(crate) fn check_for_loaded( mut blueprint_assets_to_load: Query< - (Entity, Option<&Name>, &mut AssetsToLoad), + (Entity, &mut AssetsToLoad), With, >, asset_server: Res, mut commands: Commands, ) { - for (entity, entity_name, mut assets_to_load) in blueprint_assets_to_load.iter_mut() { + 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); - println!( - "loading {}: // load state: {:?}", - tracker.name, - asset_server.load_state(asset_id) - ); - - // FIXME: hack for now - let mut failed = false; // asset_server.load_state(asset_id) == bevy::asset::LoadState::Failed(_error); - match asset_server.load_state(asset_id) { - bevy::asset::LoadState::Failed(_) => failed = true, - _ => {} - } - tracker.loaded = loaded || failed; - if loaded || failed { + 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); + // 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::() - .remove::(); + .remove::(); } } } -pub(crate) fn spawn_from_blueprints2( +pub(crate) fn spawn_from_blueprints( spawn_placeholders: Query< ( Entity, &BlueprintName, - &BlueprintPath, Option<&Transform>, Option<&Parent>, + Option<&Library>, Option<&AddToGameWorld>, Option<&Name>, ), @@ -244,25 +214,44 @@ pub(crate) fn spawn_from_blueprints2( mut game_world: Query>, assets_gltf: Res>, + mut graphs: ResMut>, asset_server: Res, blueprints_config: Res, children: Query<&Children>, ) { - for (entity, blupeprint_name, blueprint_path, transform, original_parent, add_to_world, name) in - spawn_placeholders.iter() + for ( + entity, + blupeprint_name, + transform, + original_parent, + library_override, + add_to_world, + name, + ) in spawn_placeholders.iter() { - info!( - "attempting to spawn blueprint {:?} for entity {:?}, id: {:?}, parent:{:?}", + debug!( + "attempting to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}", blupeprint_name.0, name, entity, original_parent ); - // info!("attempting to spawn {:?}", model_path); - let model_handle: Handle = asset_server.load(blueprint_path.0.clone()); // FIXME: kinda weird now + let what = &blupeprint_name.0; + let model_file_name = format!("{}.{}", &what, &blueprints_config.format); - let gltf = assets_gltf - .get(&model_handle) - .unwrap_or_else(|| panic!("gltf file {:?} should have been loaded", &blueprint_path.0)); + // 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 = 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 @@ -286,10 +275,16 @@ pub(crate) fn spawn_from_blueprints2( } } + let mut graph = AnimationGraph::new(); let mut named_animations: HashMap> = HashMap::new(); - for (key, value) in gltf.named_animations.iter() { - named_animations.insert(key.to_string(), value.clone()); + let mut named_indices: HashMap = HashMap::new(); + + for (key, clip) in gltf.named_animations.iter() { + named_animations.insert(key.to_string(), clip.clone()); + let animation_index = graph.add_clip(clip.clone(), 1.0, graph.root); + named_indices.insert(key.to_string(), animation_index); } + let graph = graphs.add(graph); commands.entity(entity).insert(( SceneBundle { @@ -297,13 +292,13 @@ pub(crate) fn spawn_from_blueprints2( transform: transforms, ..Default::default() }, - Spawned, - BlueprintInstanceReady, // FIXME: not sure if this is should be added here or in the post process - OriginalChildren(original_children), - BlueprintAnimations { - // these are animations specific to the inside of the blueprint - named_animations: named_animations, //gltf.named_animations.clone(), + Animations { + named_animations, + named_indices, + graph }, + Spawned, + OriginalChildren(original_children), )); if add_to_world.is_some() { diff --git a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs index f3336bf..b53f4d7 100644 --- a/crates/bevy_gltf_blueprints/src/spawn_post_process.rs +++ b/crates/bevy_gltf_blueprints/src/spawn_post_process.rs @@ -5,7 +5,7 @@ use bevy::prelude::*; use bevy::scene::SceneInstance; // use bevy::utils::hashbrown::HashSet; -use super::{BlueprintAnimationPlayerLink, BlueprintAnimations}; +use super::{AnimationPlayerLink, Animations}; use super::{SpawnHere, Spawned}; use crate::{ AssetsToLoad, BlueprintAssetsLoaded, CopyComponents, InBlueprint, NoInBlueprint, @@ -24,7 +24,7 @@ pub(crate) fn spawned_blueprint_post_process( Entity, &Children, &OriginalChildren, - &BlueprintAnimations, + &Animations, Option<&NoInBlueprint>, Option<&Name>, ), @@ -38,7 +38,7 @@ pub(crate) fn spawned_blueprint_post_process( for (original, children, original_children, animations, no_inblueprint, name) in unprocessed_entities.iter() { - info!("post processing blueprint for entity {:?}", name); + debug!("post processing blueprint for entity {:?}", name); if children.len() == 0 { warn!("timing issue ! no children found, please restart your bevy app (bug being investigated)"); @@ -85,19 +85,16 @@ pub(crate) fn spawned_blueprint_post_process( // FIXME: stopgap solution: since we cannot use an AnimationPlayer at the root entity level // and we cannot update animation clips so that the EntityPaths point to one level deeper, // BUT we still want to have some marker/control at the root entity level, we add this - commands - .entity(original) - .insert(BlueprintAnimationPlayerLink(added)); + commands.entity(original).insert(AnimationPlayerLink(added)); } } } commands.entity(original).remove::(); commands.entity(original).remove::(); - // commands.entity(original).remove::>(); // FIXME: if we delete the handle to the scene, things get despawned ! not what we want - //commands.entity(original).remove::(); // 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::(); + commands.entity(original).remove::>(); + commands.entity(original).remove::>(); // 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::(); commands.entity(root_entity).despawn_recursive(); - info!("DONE WITH POST PROCESS"); } } diff --git a/crates/bevy_gltf_components/Cargo.toml b/crates/bevy_gltf_components/Cargo.toml index 9933da8..f1ae355 100644 --- a/crates/bevy_gltf_components/Cargo.toml +++ b/crates/bevy_gltf_components/Cargo.toml @@ -14,9 +14,9 @@ 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", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } serde = "1.0.188" ron = "0.8.1" [dev-dependencies] -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file +bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/bevy_gltf_components/README.md b/crates/bevy_gltf_components/README.md index 91f3c2e..96610e5 100644 --- a/crates/bevy_gltf_components/README.md +++ b/crates/bevy_gltf_components/README.md @@ -4,7 +4,9 @@ [![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking) -# bevy_gltf_components +# bevy_gltf_components (deprecated in favor of Blenvy) + +> bevy_gltf_components has been deprecated in favor of its successor [Blenvy](https://crates.io/crates/blenvy), part of the [Blenvy project](https://github.com/kaosat-dev/Blenvy). No further development or maintenance will be done for Bevy bevy_gltf_components. See [#194](https://github.com/kaosat-dev/Blenvy/issues/194) for background. This crate allows you to define [Bevy](https://bevyengine.org/) components direclty inside gltf files and instanciate the components on the Bevy side. @@ -23,8 +25,8 @@ Here's a minimal usage example: ```toml # Cargo.toml [dependencies] -bevy="0.13" -bevy_gltf_components = { version = "0.5"} +bevy="0.14" +bevy_gltf_components = { version = "0.6"} ``` @@ -60,7 +62,7 @@ bevy_gltf_components = { version = "0.5"} Add the following to your `[dependencies]` section in `Cargo.toml`: ```toml -bevy_gltf_components = "0.5" +bevy_gltf_components = "0.6" ``` Or use `cargo add`: @@ -78,78 +80,17 @@ Use the default configuration: ComponentsFromGltfPlugin::default() ``` -As of v0.6 Legacy mode has been removed , you can emulate it using a system that should run BEFORE bevy_gltf_components - -```rust no run - if simplified_types { - if let TypeInfo::TupleStruct(info) = type_registration.type_info() { - // we handle tupple strucs with only one field differently, as Blender's custom properties with custom ui (float, int, bool, etc) always give us a tupple struct - if info.field_len() == 1 { - let field = info - .field_at(0) - .expect("we should always have at least one field here"); - let field_name = field.type_path(); - let mut formated = parsed_value.clone(); - match field_name { - "f32" => { - formated = parsed_value.parse::().unwrap().to_string(); - } - "f64" => { - formated = parsed_value.parse::().unwrap().to_string(); - } - "u8" => { - formated = parsed_value.parse::().unwrap().to_string(); - } - "u16" => { - formated = parsed_value.parse::().unwrap().to_string(); - } - "u32" => { - formated = parsed_value.parse::().unwrap().to_string(); - } - "u64" => { - formated = parsed_value.parse::().unwrap().to_string(); - } - "u128" => { - formated = parsed_value.parse::().unwrap().to_string(); - } - "glam::Vec2" => { - let parsed: Vec = ron::from_str(&parsed_value).unwrap(); - formated = format!("(x:{},y:{})", parsed[0], parsed[1]); - } - "glam::Vec3" => { - let parsed: Vec = ron::from_str(&parsed_value).unwrap(); - formated = - format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]); - } - "bevy_render::color::Color" => { - let parsed: Vec = ron::from_str(&parsed_value).unwrap(); - if parsed.len() == 3 { - formated = format!( - "Rgba(red:{},green:{},blue:{}, alpha: 1.0)", - parsed[0], parsed[1], parsed[2] - ); - } - if parsed.len() == 4 { - formated = format!( - "Rgba(red:{},green:{},blue:{}, alpha:{})", - parsed[0], parsed[1], parsed[2], parsed[3] - ); - } - } - _ => {} - } - - parsed_value = format!("({formated})"); - } - } - - if parsed_value.is_empty() { - parsed_value = "()".to_string(); - } - } +Or disable the legacy mode: (enabled by default) +```rust no_run +ComponentsFromGltfPlugin{legacy_mode: false} ``` +You **need** to disable legacy mode if you want to use the [```bevy_components```](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/bevy_components) Blender addon + the [```bevy_registry_export crate```](https://crates.io/crates/bevy_registry_export) ! +As it create custom properties that are writen in real **ron** file format +instead of a simplified version (the one in the legacy mode) + +> Note: the legacy mode support will be dropped in future versions, and the default behaviour will be NO legacy mode ## SystemSet @@ -188,6 +129,7 @@ The main branch is compatible with the latest Bevy release, while the branch `be Compatibility of `bevy_gltf_components` versions: | `bevy_gltf_components` | `bevy` | | :-- | :-- | +| `0.6` | `0.14` | | `0.5` | `0.13` | | `0.2 - 0.4` | `0.12` | | `0.1` | `0.11` | diff --git a/crates/bevy_gltf_components/src/lib.rs b/crates/bevy_gltf_components/src/lib.rs index 79af3d7..ccba12f 100644 --- a/crates/bevy_gltf_components/src/lib.rs +++ b/crates/bevy_gltf_components/src/lib.rs @@ -10,7 +10,13 @@ pub use process_gltfs::*; pub mod blender_settings; use bevy::{ - ecs::{component::Component, reflect::ReflectComponent, system::Resource}, + app::Startup, + ecs::{ + component::Component, + reflect::ReflectComponent, + system::{Res, Resource}, + }, + log::warn, prelude::{App, IntoSystemConfigs, Plugin, SystemSet, Update}, reflect::Reflect, }; @@ -60,16 +66,34 @@ pub enum GltfComponentsSet { } #[derive(Clone, Resource)] -pub struct GltfComponentsConfig {} +pub struct GltfComponentsConfig { + pub(crate) legacy_mode: bool, +} -#[derive(Default)] -pub struct ComponentsFromGltfPlugin {} +pub struct ComponentsFromGltfPlugin { + pub legacy_mode: bool, +} + +impl Default for ComponentsFromGltfPlugin { + fn default() -> Self { + Self { legacy_mode: true } + } +} + +fn check_for_legacy_mode(gltf_components_config: Res) { + if gltf_components_config.legacy_mode { + warn!("using simplified component definitions is deprecated since 0.3, prefer defining components with real ron values (use the bevy_components tool for Blender for simplicity) "); + } +} impl Plugin for ComponentsFromGltfPlugin { fn build(&self, app: &mut App) { app.add_plugins(blender_settings::plugin) .register_type::() - .insert_resource(GltfComponentsConfig {}) + .insert_resource(GltfComponentsConfig { + legacy_mode: self.legacy_mode, + }) + .add_systems(Startup, check_for_legacy_mode) .add_systems( Update, (add_components_from_gltf_extras).in_set(GltfComponentsSet::Injection), diff --git a/crates/bevy_gltf_components/src/process_gltfs.rs b/crates/bevy_gltf_components/src/process_gltfs.rs index 4989374..a37f537 100644 --- a/crates/bevy_gltf_components/src/process_gltfs.rs +++ b/crates/bevy_gltf_components/src/process_gltfs.rs @@ -6,67 +6,23 @@ use bevy::{ reflect::{AppTypeRegistry, ReflectComponent}, world::World, }, - gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras}, + gltf::GltfExtras, hierarchy::Parent, log::debug, reflect::{Reflect, TypeRegistration}, utils::HashMap, }; -use crate::{ronstring_to_reflect_component, GltfProcessed}; - -// , mut entity_components: HashMap, TypeRegistration)>> -fn find_entity_components( - entity: Entity, - name: &Name, - parent: &Parent, - reflect_components: Vec<(Box, TypeRegistration)>, - entity_components: &HashMap, TypeRegistration)>>, -) -> (Entity, Vec<(Box, TypeRegistration)>) { - // we assign the components specified /xxx_components objects to their parent node - let mut target_entity = entity; - // if the node contains "components" or ends with "_pa" (ie add to parent), the components will not be added to the entity itself but to its parent - // this is mostly used for Blender collections - if name.as_str().contains("components") || name.as_str().ends_with("_pa") { - debug!("adding components to parent"); - target_entity = parent.get(); - } - debug!("adding to {:?}", target_entity); - - // if there where already components set to be added to this entity (for example when entity_data was refering to a parent), update the vec of entity_components accordingly - // this allows for example blender collection to provide basic ecs data & the instances to override/ define their own values - if entity_components.contains_key(&target_entity) { - let mut updated_components: Vec<(Box, TypeRegistration)> = Vec::new(); - let current_components = &entity_components[&target_entity]; - // first inject the current components - for (component, type_registration) in current_components { - updated_components.push((component.clone_value(), type_registration.clone())); - } - // then inject the new components: this also enables overwrite components set in the collection - for (component, type_registration) in reflect_components { - updated_components.push((component.clone_value(), type_registration)); - } - return (target_entity, updated_components); - //entity_components.insert(target_entity, updated_components); - } else { - return (target_entity, reflect_components); - // entity_components.insert(target_entity, reflect_components); - } -} +use crate::{ronstring_to_reflect_component, GltfComponentsConfig, GltfProcessed}; /// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection pub fn add_components_from_gltf_extras(world: &mut World) { let mut extras = world.query_filtered::<(Entity, &Name, &GltfExtras, &Parent), (Added, Without)>(); - - let mut scene_extras = world.query_filtered::<(Entity, &Name, &GltfSceneExtras, &Parent), (Added, Without)>(); - let mut mesh_extras = world.query_filtered::<(Entity, &Name, &GltfMeshExtras, &Parent), (Added, Without)>(); - let mut material_extras = world.query_filtered::<(Entity, &Name, &GltfMaterialExtras, &Parent), (Added, Without)>(); - let mut entity_components: HashMap, TypeRegistration)>> = HashMap::new(); - // let gltf_components_config = world.resource::(); + let gltf_components_config = world.resource::(); for (entity, name, extra, parent) in extras.iter(world) { debug!( @@ -76,56 +32,40 @@ pub fn add_components_from_gltf_extras(world: &mut World) { let type_registry: &AppTypeRegistry = world.resource(); let type_registry = type_registry.read(); - let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); - let (target_entity, updated_components) = - find_entity_components(entity, name, parent, reflect_components, &entity_components); - entity_components.insert(target_entity, updated_components); - } - - for (entity, name, extra, parent) in scene_extras.iter(world) { - debug!( - "Name: {}, entity {:?}, parent: {:?}, scene_extras {:?}", - name, entity, parent, extra + let reflect_components = ronstring_to_reflect_component( + &extra.value, + &type_registry, + gltf_components_config.legacy_mode, ); - let type_registry: &AppTypeRegistry = world.resource(); - let type_registry = type_registry.read(); - let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); + // we assign the components specified /xxx_components objects to their parent node + let mut target_entity = entity; + // if the node contains "components" or ends with "_pa" (ie add to parent), the components will not be added to the entity itself but to its parent + // this is mostly used for Blender collections + if name.as_str().contains("components") || name.as_str().ends_with("_pa") { + debug!("adding components to parent"); + target_entity = parent.get(); + } + debug!("adding to {:?}", target_entity); - let (target_entity, updated_components) = - find_entity_components(entity, name, parent, reflect_components, &entity_components); - entity_components.insert(target_entity, updated_components); - } - - for (entity, name, extra, parent) in mesh_extras.iter(world) { - debug!( - "Name: {}, entity {:?}, parent: {:?}, mesh_extras {:?}", - name, entity, parent, extra - ); - - let type_registry: &AppTypeRegistry = world.resource(); - let type_registry = type_registry.read(); - let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); - - let (target_entity, updated_components) = - find_entity_components(entity, name, parent, reflect_components, &entity_components); - entity_components.insert(target_entity, updated_components); - } - - for (entity, name, extra, parent) in material_extras.iter(world) { - debug!( - "Name: {}, entity {:?}, parent: {:?}, material_extras {:?}", - name, entity, parent, extra - ); - - let type_registry: &AppTypeRegistry = world.resource(); - let type_registry = type_registry.read(); - let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry); - - let (target_entity, updated_components) = - find_entity_components(entity, name, parent, reflect_components, &entity_components); - entity_components.insert(target_entity, updated_components); + // if there where already components set to be added to this entity (for example when entity_data was refering to a parent), update the vec of entity_components accordingly + // this allows for example blender collection to provide basic ecs data & the instances to override/ define their own values + if entity_components.contains_key(&target_entity) { + let mut updated_components: Vec<(Box, TypeRegistration)> = Vec::new(); + let current_components = &entity_components[&target_entity]; + // first inject the current components + for (component, type_registration) in current_components { + updated_components.push((component.clone_value(), type_registration.clone())); + } + // then inject the new components: this also enables overwrite components set in the collection + for (component, type_registration) in reflect_components { + updated_components.push((component.clone_value(), type_registration)); + } + entity_components.insert(target_entity, updated_components); + } else { + entity_components.insert(target_entity, reflect_components); + } } for (entity, components) in entity_components { diff --git a/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs b/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs index 483c06e..7506c89 100644 --- a/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs +++ b/crates/bevy_gltf_components/src/ronstring_to_reflect_component.rs @@ -1,6 +1,6 @@ use bevy::log::{debug, warn}; use bevy::reflect::serde::ReflectDeserializer; -use bevy::reflect::{Reflect, TypeRegistration, TypeRegistry}; +use bevy::reflect::{Reflect, TypeInfo, TypeRegistration, TypeRegistry}; use bevy::utils::HashMap; use ron::Value; use serde::de::DeserializeSeed; @@ -10,102 +10,105 @@ use super::capitalize_first_letter; pub fn ronstring_to_reflect_component( ron_string: &str, type_registry: &TypeRegistry, + simplified_types: bool, ) -> Vec<(Box, TypeRegistration)> { let lookup: HashMap = ron::from_str(ron_string).unwrap(); let mut components: Vec<(Box, TypeRegistration)> = Vec::new(); - // println!("ron_string {:?}", ron_string); - for (name, value) in lookup.into_iter() { - let parsed_value: String = match value.clone() { - Value::String(str) => str, - _ => ron::to_string(&value).unwrap().to_string(), - }; - - if name.as_str() == "bevy_components" { - bevy_components_string_to_components(parsed_value, type_registry, &mut components); - } else { - components_string_to_components( - name, - value, - parsed_value, - type_registry, - &mut components, - ); - } - } - components -} - -fn components_string_to_components( - name: String, - value: Value, - parsed_value: String, - type_registry: &TypeRegistry, - components: &mut Vec<(Box, TypeRegistration)>, -) { - let type_string = name.replace("component: ", "").trim().to_string(); - let capitalized_type_name = capitalize_first_letter(type_string.as_str()); - - if let Some(type_registration) = - type_registry.get_with_short_type_path(capitalized_type_name.as_str()) - { - debug!("TYPE INFO {:?}", type_registration.type_info()); - - let ron_string = format!( - "{{ \"{}\":{} }}", - type_registration.type_info().type_path(), - parsed_value - ); - - // usefull to determine what an entity looks like Serialized - /*let test_struct = CameraRenderGraph::new("name"); - let serializer = ReflectSerializer::new(&test_struct, &type_registry); - let serialized = - ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap(); - println!("serialized Component {}", serialized);*/ - - debug!("component data ron string {}", ron_string); - let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()) - .expect("deserialzer should have been generated from string"); - let reflect_deserializer = ReflectDeserializer::new(type_registry); - let component = reflect_deserializer - .deserialize(&mut deserializer) - .unwrap_or_else(|_| { - panic!( - "failed to deserialize component {} with value: {:?}", - name, value - ) - }); - - debug!("component {:?}", component); - debug!("real type {:?}", component.get_represented_type_info()); - components.push((component, type_registration.clone())); - debug!("found type registration for {}", capitalized_type_name); - } else { - warn!("no type registration for {}", capitalized_type_name); - } -} - -fn bevy_components_string_to_components( - parsed_value: String, - type_registry: &TypeRegistry, - components: &mut Vec<(Box, TypeRegistration)>, -) { - let lookup: HashMap = ron::from_str(&parsed_value).unwrap(); for (key, value) in lookup.into_iter() { - let parsed_value: String = match value.clone() { - Value::String(str) => str, - _ => ron::to_string(&value).unwrap().to_string(), - }; + let type_string = key.replace("component: ", "").trim().to_string(); + let capitalized_type_name = capitalize_first_letter(type_string.as_str()); - if let Some(type_registration) = type_registry.get_with_type_path(key.as_str()) { + let mut parsed_value: String; + match value.clone() { + Value::String(str) => { + parsed_value = str; + } + _ => parsed_value = ron::to_string(&value).unwrap().to_string(), + } + + if let Some(type_registration) = + type_registry.get_with_short_type_path(capitalized_type_name.as_str()) + { debug!("TYPE INFO {:?}", type_registration.type_info()); + if simplified_types { + if let TypeInfo::TupleStruct(info) = type_registration.type_info() { + // we handle tupple strucs with only one field differently, as Blender's custom properties with custom ui (float, int, bool, etc) always give us a tupple struct + if info.field_len() == 1 { + let field = info + .field_at(0) + .expect("we should always have at least one field here"); + let field_name = field.type_path(); + let mut formated = parsed_value.clone(); + match field_name { + "f32" => { + formated = parsed_value.parse::().unwrap().to_string(); + } + "f64" => { + formated = parsed_value.parse::().unwrap().to_string(); + } + "u8" => { + formated = parsed_value.parse::().unwrap().to_string(); + } + "u16" => { + formated = parsed_value.parse::().unwrap().to_string(); + } + "u32" => { + formated = parsed_value.parse::().unwrap().to_string(); + } + "u64" => { + formated = parsed_value.parse::().unwrap().to_string(); + } + "u128" => { + formated = parsed_value.parse::().unwrap().to_string(); + } + "glam::Vec2" => { + let parsed: Vec = ron::from_str(&parsed_value).unwrap(); + formated = format!("(x:{},y:{})", parsed[0], parsed[1]); + } + "glam::Vec3" => { + let parsed: Vec = ron::from_str(&parsed_value).unwrap(); + formated = + format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]); + } + "bevy_render::color::Color" => { + let parsed: Vec = ron::from_str(&parsed_value).unwrap(); + if parsed.len() == 3 { + formated = format!( + "Rgba(red:{},green:{},blue:{}, alpha: 1.0)", + parsed[0], parsed[1], parsed[2] + ); + } + if parsed.len() == 4 { + formated = format!( + "Rgba(red:{},green:{},blue:{}, alpha:{})", + parsed[0], parsed[1], parsed[2], parsed[3] + ); + } + } + _ => {} + } + parsed_value = format!("({formated})"); + } + } + + if parsed_value.is_empty() { + parsed_value = "()".to_string(); + } + } let ron_string = format!( "{{ \"{}\":{} }}", type_registration.type_info().type_path(), parsed_value ); + // usefull to determine what an entity looks like Serialized + /*let test_struct = CameraRenderGraph::new("name"); + let serializer = ReflectSerializer::new(&test_struct, &type_registry); + let serialized = + ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap(); + println!("serialized Component {}", serialized);*/ + debug!("component data ron string {}", ron_string); let mut deserializer = ron::Deserializer::from_str(ron_string.as_str()) .expect("deserialzer should have been generated from string"); @@ -122,9 +125,10 @@ fn bevy_components_string_to_components( debug!("component {:?}", component); debug!("real type {:?}", component.get_represented_type_info()); components.push((component, type_registration.clone())); - debug!("found type registration for {}", key); + debug!("found type registration for {}", capitalized_type_name); } else { - warn!("no type registration for {}", key); + warn!("no type registration for {}", capitalized_type_name); } } + components } diff --git a/crates/bevy_gltf_save_load/Cargo.toml b/crates/bevy_gltf_save_load/Cargo.toml index 9d64b92..a8f76c4 100644 --- a/crates/bevy_gltf_save_load/Cargo.toml +++ b/crates/bevy_gltf_save_load/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_gltf_save_load" -version = "0.4.1" +version = "0.5.0" authors = ["Mark 'kaosat-dev' Moissette"] description = "Save & load your bevy games" homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" @@ -14,8 +14,8 @@ 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", default-features = false, features = ["bevy_asset", "bevy_scene", "bevy_gltf"] } bevy_gltf_blueprints = { version = "0.11", path = "../bevy_gltf_blueprints" } [dev-dependencies] -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } +bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] } diff --git a/crates/bevy_gltf_save_load/README.md b/crates/bevy_gltf_save_load/README.md index 7079e16..aaf4cbb 100644 --- a/crates/bevy_gltf_save_load/README.md +++ b/crates/bevy_gltf_save_load/README.md @@ -3,7 +3,9 @@ [![License](https://img.shields.io/crates/l/bevy_gltf_save_load)](https://github.com/kaosat-dev/Blender_bevy_components_workflow/blob/main/crates/bevy_gltf_save_load/License.md) [![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking) -# bevy_gltf_save_load +# bevy_gltf_save_load (deprecated in favor of Blenvy) + +> bevy_gltf_save_load has been deprecated in favor of its successor [Blenvy](https://crates.io/crates/blenvy), part of the [Blenvy project](https://github.com/kaosat-dev/Blenvy). No further development or maintenance will be done for Bevy bevy_gltf_save_load. See [#194](https://github.com/kaosat-dev/Blenvy/issues/194) for background. Built upon [bevy_gltf_blueprints](https://crates.io/crates/bevy_gltf_blueprints) this crate adds the ability to easilly **save** and **load** your game worlds for [Bevy](https://bevyengine.org/) . @@ -34,9 +36,9 @@ Here's a minimal usage example: ```toml # Cargo.toml [dependencies] -bevy="0.13" -bevy_gltf_save_load = "0.4" -bevy_gltf_blueprints = "0.10" // also needed +bevy="0.14" +bevy_gltf_save_load = "0.5" +bevy_gltf_blueprints = "0.11" // also needed ``` ```rust no_run @@ -191,6 +193,7 @@ fn main() { }, // you need to configure the blueprints plugin as well (might be pre_configured in the future, but for now you need to do it manually) BlueprintsPlugin { + library_folder: "models/library".into(), format: GltfFormat::GLB, aabbs: true, ..Default::default() @@ -297,6 +300,7 @@ The main branch is compatible with the latest Bevy release, while the branch `be Compatibility of `bevy_gltf_save_load` versions: | `bevy_gltf_save_load` | `bevy` | | :-- | :-- | +| `0.5 ` | `0.14` | | `0.4 ` | `0.13` | | `0.1 -0.3` | `0.12` | | branch `main` | `0.12` | diff --git a/crates/bevy_registry_export/Cargo.toml b/crates/bevy_registry_export/Cargo.toml index 10df80f..291f465 100644 --- a/crates/bevy_registry_export/Cargo.toml +++ b/crates/bevy_registry_export/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_registry_export" -version = "0.3.1" +version = "0.4.0" authors = ["Mark 'kaosat-dev' Moissette", "Pascal 'Killercup' Hertleif"] description = "Allows you to create a Json export of all your components/ registered types of your Bevy app/game" homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow" @@ -11,11 +11,11 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_scene"] } -bevy_reflect = { version = "0.14.0-rc.3", default-features = false } -bevy_app = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_reflect"] } -bevy_ecs = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_reflect"] } +bevy = { version = "0.14", default-features = false, features = ["bevy_scene"] } +bevy_reflect = { version = "0.14", default-features = false } +bevy_app = { version = "0.14", default-features = false, features = ["bevy_reflect"] } +bevy_ecs = { version = "0.14", default-features = false, features = ["bevy_reflect"] } serde_json = "1.0.108" [dev-dependencies] -bevy = { version = "0.14.0-rc.3", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file +bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] } \ No newline at end of file diff --git a/crates/bevy_registry_export/README.md b/crates/bevy_registry_export/README.md index 561131d..c8bac13 100644 --- a/crates/bevy_registry_export/README.md +++ b/crates/bevy_registry_export/README.md @@ -3,10 +3,13 @@ [![License](https://img.shields.io/crates/l/bevy_registry_export)](https://github.com/kaosat-dev/Blender_bevy_components_workflow/blob/main/crates/bevy_registry_export/License.md) [![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking) -# bevy_registry_export +# bevy_registry_export (deprecated in favor of Blenvy) + +> bevy_registry_export has been deprecated in favor of its successor [Blenvy](https://crates.io/crates/blenvy), part of the [Blenvy project](https://github.com/kaosat-dev/Blenvy). No further development or maintenance will be done for Bevy bevy_registry_export. See [#194](https://github.com/kaosat-dev/Blenvy/issues/194) for background. + This plugin allows you to create a Json export of all your components/ registered types. -Its main use case is as a backbone for the [```blenvy``` Blender add-on](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/blenvy), that allows you to add & edit components directly in Blender, using the actual type definitions from Bevy +Its main use case is as a backbone for the [```bevy_components``` Blender add-on](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/bevy_components), that allows you to add & edit components directly in Blender, using the actual type definitions from Bevy (and any of your custom types & components that you register in Bevy). @@ -17,8 +20,8 @@ Here's a minimal usage example: ```toml # Cargo.toml [dependencies] -bevy="0.13" -bevy_registry_export = "0.3" +bevy="0.14" +bevy_registry_export = "0.4" ``` ```rust no_run @@ -44,7 +47,7 @@ take a look at the [example](https://github.com/kaosat-dev/Blender_bevy_componen Add the following to your `[dependencies]` section in `Cargo.toml`: ```toml -bevy_registry_export = "0.3" +bevy_registry_export = "0.4" ``` @@ -100,6 +103,8 @@ fn main() { All examples are here: +> the examples use ```bevy_gltf_blueprints``` with the **legacy_mode** set to **FALSE** as the new custom properties generated by the Blender add-on require newer/ non legacy logic. + - https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/examples/bevy_registry_export/basic @@ -110,6 +115,7 @@ The main branch is compatible with the latest Bevy release, while the branch `be Compatibility of `bevy_registry_export` versions: | `bevy_registry_export` | `bevy` | `bevy_components (Blender add-on)` | | :-- | :-- |:-- | +| `0.4 ` | `0.14` | `0.3` | | `0.3 ` | `0.13` | `0.3` | | `0.2 ` | `0.12` | `0.3` | | `0.1 ` | `0.12` | `0.1 -0.2` | diff --git a/crates/bevy_registry_export/src/export_types.rs b/crates/bevy_registry_export/src/export_types.rs index 5bda876..8a06ebf 100644 --- a/crates/bevy_registry_export/src/export_types.rs +++ b/crates/bevy_registry_export/src/export_types.rs @@ -17,28 +17,18 @@ pub fn export_types(world: &mut World) { let asset_root = world.resource::(); let registry_save_path = Path::join(&asset_root.0, &config.save_path); + println!("registry_save_path {}", registry_save_path.display()); let writer = File::create(registry_save_path).expect("should have created schema file"); - let components_to_filter_out = &config.component_filter.clone(); - let resources_to_filter_out = &config.resource_filter.clone(); - let types = world.resource_mut::(); let types = types.read(); - let schemas = types - .iter() - .filter(|type_info| { - let type_id = type_info.type_id(); - components_to_filter_out.is_allowed_by_id(type_id) - && resources_to_filter_out.is_allowed_by_id(type_id) - }) - .map(export_type) - .collect::>(); + let schemas = types.iter().map(export_type).collect::>(); serde_json::to_writer_pretty( writer, &json!({ "$schema": "https://json-schema.org/draft/2020-12/schema", - "long_name": "bevy component registry schema", + "title": "bevy component registry schema", "$defs": schemas, }), ) @@ -67,7 +57,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { json!({ "type": "object", "typeInfo": "Struct", - "long_name": t.type_path(), + "title": t.type_path(), "properties": properties, "additionalProperties": false, "required": info @@ -85,7 +75,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { json!({ "type": "string", "typeInfo": "Enum", - "long_name": t.type_path(), + "title": t.type_path(), "oneOf": info .iter() .map(|variant| match variant { @@ -104,12 +94,12 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { VariantInfo::Struct(v) => json!({ "type": "object", "typeInfo": "Struct", - "long_name": v.name(), + "title": v.name(), "short_name": v.name().split("::").last().unwrap_or(v.name()), "properties": v .iter() .enumerate() - .map(|(variant_idx, field)| (field.name().to_owned(), add_min_max(json!({"type": typ(field.type_path()), "long_name": field.name()}), reg, field_idx, Some(variant_idx)))) + .map(|(variant_idx, field)| (field.name().to_owned(), add_min_max(json!({"type": typ(field.type_path()), "title": field.name()}), reg, field_idx, Some(variant_idx)))) .collect::>(), "additionalProperties": false, "required": v @@ -121,7 +111,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { VariantInfo::Tuple(v) => json!({ "type": "array", "typeInfo": "Tuple", - "long_name": v.name(), + "title": v.name(), "short_name":v.name(), "prefixItems": v .iter() @@ -131,7 +121,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { "items": false, }), VariantInfo::Unit(v) => json!({ - "long_name": v.name(), + "title": v.name(), }), }) .collect::>(); @@ -139,13 +129,13 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { json!({ "type": "object", "typeInfo": "Enum", - "long_name": t.type_path(), + "title": t.type_path(), "oneOf": variants, }) } } TypeInfo::TupleStruct(info) => json!({ - "long_name": t.type_path(), + "title": t.type_path(), "type": "array", "typeInfo": "TupleStruct", "prefixItems": info @@ -157,27 +147,26 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { }), TypeInfo::List(info) => { json!({ - "long_name": t.type_path(), + "title": t.type_path(), "type": "array", "typeInfo": "List", "items": json!({"type": typ(info.item_type_path_table().path())}), }) } TypeInfo::Array(info) => json!({ - "long_name": t.type_path(), + "title": t.type_path(), "type": "array", "typeInfo": "Array", "items": json!({"type": typ(info.item_type_path_table().path())}), }), TypeInfo::Map(info) => json!({ - "long_name": t.type_path(), + "title": t.type_path(), "type": "object", "typeInfo": "Map", - "valueType": json!({"type": typ(info.value_type_path_table().path())}), - "keyType": json!({"type": typ(info.key_type_path_table().path())}), + "additionalProperties": json!({"type": typ(info.value_type_path_table().path())}), }), TypeInfo::Tuple(info) => json!({ - "long_name": t.type_path(), + "title": t.type_path(), "type": "array", "typeInfo": "Tuple", "prefixItems": info @@ -188,7 +177,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) { "items": false, }), TypeInfo::Value(info) => json!({ - "long_name": t.type_path(), + "title": t.type_path(), "type": map_json_type(info.type_path()), "typeInfo": "Value", }), diff --git a/crates/bevy_registry_export/src/lib.rs b/crates/bevy_registry_export/src/lib.rs index 2386241..eef5136 100644 --- a/crates/bevy_registry_export/src/lib.rs +++ b/crates/bevy_registry_export/src/lib.rs @@ -16,9 +16,9 @@ use bevy::{ pub struct ExportComponentsConfig { pub(crate) save_path: PathBuf, #[allow(dead_code)] - pub(crate) component_filter: SceneFilter, + pub(crate) component_filter: SceneFilter, // unused for now #[allow(dead_code)] - pub(crate) resource_filter: SceneFilter, + pub(crate) resource_filter: SceneFilter, // unused for now } pub struct ExportRegistryPlugin { @@ -30,8 +30,8 @@ pub struct ExportRegistryPlugin { impl Default for ExportRegistryPlugin { fn default() -> Self { Self { - component_filter: SceneFilter::default(), - resource_filter: SceneFilter::default(), + component_filter: SceneFilter::default(), // unused for now + resource_filter: SceneFilter::default(), // unused for now save_path: PathBuf::from("registry.json"), // relative to assets folder } } diff --git a/crates/blenvy/README.md b/crates/blenvy/README.md index 75ebbcf..831bdb6 100644 --- a/crates/blenvy/README.md +++ b/crates/blenvy/README.md @@ -19,7 +19,7 @@ This crate allows you to Particularly useful when using [Blender](https://www.blender.org/) as an editor for the [Bevy](https://bevyengine.org/) game engine, combined with the Blender add-on that do a lot of the work for you - [blenvy](https://github.com/kaosat-dev/Blenvy/tree/main/tools/blenvy) - allows you to create a Json export of all your components/ registered types. -Its main use case is as a backbone for the [```blenvy``` Blender add-on](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/blenvy), that allows you to add & edit components directly in Blender, using the actual type definitions from Bevy +Its main use case is as a backbone for the [```blenvy``` Blender add-on](https://github.com/kaosat-dev/Blenvy/tree/main/tools/blenvy), that allows you to add & edit components directly in Blender, using the actual type definitions from Bevy (and any of your custom types & components that you register in Bevy). - adds the ability to easilly **save** and **load** your game worlds for [Bevy](https://bevyengine.org/) . @@ -33,7 +33,7 @@ Its main use case is as a backbone for the [```blenvy``` Blender add-on](https:/ * ability to specify **which resources** to save or to exclude * small(er) save files (only a portion of the entities is saved) -Particularly useful when using [Blender](https://www.blender.org/) as an editor for the [Bevy](https://bevyengine.org/) game engine, combined with the [Blender plugin](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/blenvy) that does a lot of the work for you (including spliting generating seperate gltf files for your static vs dynamic assets) +Particularly useful when using [Blender](https://www.blender.org/) as an editor for the [Bevy](https://bevyengine.org/) game engine, combined with the [Blender plugin](https://github.com/kaosat-dev/Blenvy/tree/main/tools/blenvy) that does a lot of the work for you (including spliting generating seperate gltf files for your static vs dynamic assets) ## Usage diff --git a/crates/blenvy/src/blueprints/spawn_from_blueprints.rs b/crates/blenvy/src/blueprints/spawn_from_blueprints.rs index 239afe0..1516fa5 100644 --- a/crates/blenvy/src/blueprints/spawn_from_blueprints.rs +++ b/crates/blenvy/src/blueprints/spawn_from_blueprints.rs @@ -354,12 +354,12 @@ pub(crate) fn blueprints_assets_loaded( // prepare data for animations let mut graph = AnimationGraph::new(); let mut named_animations: HashMap> = HashMap::new(); - let mut animation_indices: HashMap = HashMap::new(); + let mut named_indices: HashMap = HashMap::new(); for (key, clip) in blueprint_gltf.named_animations.iter() { named_animations.insert(key.to_string(), clip.clone()); let animation_index = graph.add_clip(clip.clone(), 1.0, graph.root); - animation_indices.insert(key.to_string(), animation_index); + named_indices.insert(key.to_string(), animation_index); } let graph = graphs.add(graph); @@ -377,7 +377,7 @@ pub(crate) fn blueprints_assets_loaded( // TODO: perhaps swap this out with SceneAnimations depending on whether we are spawning a level or a simple blueprint // these are animations specific to the blueprint named_animations, - named_indices: animation_indices, + named_indices, graph, }, ));