Compare commits
2 Commits
5f955c1a53
...
a618e0035e
Author | SHA1 | Date |
---|---|---|
kaosat.dev | a618e0035e | |
kaosat.dev | 3a8844b7a1 |
|
@ -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"] }
|
||||
bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] }
|
|
@ -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` |
|
||||
|
|
|
@ -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<String, Handle<AnimationClip>>,
|
||||
pub named_indices: HashMap<String, AnimationNodeIndex>,
|
||||
pub graph: Handle<AnimationGraph>,
|
||||
}
|
||||
|
||||
#[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<String, Handle<AnimationClip>>,
|
||||
}
|
||||
|
||||
#[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<AnimationInfo>,
|
||||
}
|
||||
|
||||
#[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<String, HashMap<u32, Vec<String>>>);
|
||||
|
||||
/// 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<Assets<AnimationClip>>,
|
||||
animation_graphs: Res<Assets<AnimationGraph>>,
|
||||
mut animation_marker_events: EventWriter<AnimationMarkerReached>,
|
||||
) {
|
||||
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<Assets<AnimationClip>>,
|
||||
mut animation_marker_events: EventWriter<AnimationMarkerReached>,
|
||||
) {
|
||||
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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<String, Aabb>, // cache for aabbs
|
||||
|
||||
pub(crate) material_library: bool,
|
||||
pub(crate) material_library_folder: PathBuf,
|
||||
pub(crate) material_library_cache: HashMap<String, Handle<StandardMaterial>>,
|
||||
}
|
||||
|
||||
|
@ -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<BluePrintsConfig>) -> bool {
|
|||
|
||||
impl Plugin for BlueprintsPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugins(ComponentsFromGltfPlugin {})
|
||||
.register_type::<BlueprintName>()
|
||||
.register_type::<BlueprintPath>()
|
||||
.register_type::<MaterialInfo>()
|
||||
.register_type::<SpawnHere>()
|
||||
.register_type::<BlueprintAnimations>()
|
||||
.register_type::<SceneAnimations>()
|
||||
.register_type::<AnimationInfo>()
|
||||
.register_type::<AnimationInfos>()
|
||||
.register_type::<Vec<AnimationInfo>>()
|
||||
.register_type::<AnimationMarkers>()
|
||||
.register_type::<HashMap<u32, Vec<String>>>()
|
||||
.register_type::<HashMap<String, HashMap<u32, Vec<String>>>>()
|
||||
.add_event::<AnimationMarkerReached>()
|
||||
.register_type::<BlueprintAsset>()
|
||||
.register_type::<Vec<BlueprintAsset>>()
|
||||
.register_type::<Vec<String>>()
|
||||
.register_type::<LocalAssets>()
|
||||
.register_type::<BlueprintAssets>()
|
||||
app.add_plugins(ComponentsFromGltfPlugin {
|
||||
legacy_mode: self.legacy_mode,
|
||||
})
|
||||
.register_type::<BlueprintName>()
|
||||
.register_type::<MaterialInfo>()
|
||||
.register_type::<SpawnHere>()
|
||||
.register_type::<Animations>()
|
||||
.register_type::<BlueprintsList>()
|
||||
.register_type::<Vec<String>>()
|
||||
.register_type::<HashMap<String, Vec<String>>>()
|
||||
.insert_resource(BluePrintsConfig {
|
||||
format: self.format,
|
||||
library_folder: self.library_folder.clone(),
|
||||
|
||||
aabbs: self.aabbs,
|
||||
aabb_cache: HashMap::new(),
|
||||
|
||||
.register_type::<HashMap<String, Vec<String>>>()
|
||||
.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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Gltf>
|
||||
let material_file_handle: Handle<Gltf> = asset_server.load(materials_path.clone());
|
||||
let material_file_id = material_file_handle.id();
|
||||
|
||||
let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
|
||||
name: material_info.name.clone(),
|
||||
let asset_infos: Vec<AssetLoadTracker<Gltf>> = 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<Gltf>),
|
||||
With<BlueprintMaterialAssetsNotLoaded>,
|
||||
>,
|
||||
asset_server: Res<AssetServer>,
|
||||
|
@ -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<StandardMaterial>> = 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<Gltf> = asset_server.load(material_info.path.clone()); // FIXME: kinda weird now
|
||||
let model_handle: Handle<Gltf> = 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());
|
||||
|
|
|
@ -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<Entity>);
|
||||
|
||||
pub(crate) fn test_thingy(
|
||||
spawn_placeholders: Query<
|
||||
(Entity, &BlueprintPath),
|
||||
(Added<BlueprintPath>, Without<Spawned>, Without<SpawnHere>),
|
||||
>,
|
||||
/// helper component, is used to store the list of sub blueprints to enable automatic loading of dependend blueprints
|
||||
#[derive(Component, Reflect, Default, Debug)]
|
||||
#[reflect(Component)]
|
||||
pub struct BlueprintsList(pub HashMap<String, Vec<String>>);
|
||||
|
||||
// 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<T: bevy::prelude::Asset> {
|
||||
#[allow(dead_code)]
|
||||
pub name: String,
|
||||
pub id: AssetId<T>,
|
||||
pub loaded: bool,
|
||||
#[allow(dead_code)]
|
||||
pub handle: Handle<T>,
|
||||
}
|
||||
|
||||
/// helper component, for tracking loaded assets
|
||||
#[derive(Component, Debug)]
|
||||
pub(crate) struct AssetsToLoad<T: bevy::prelude::Asset> {
|
||||
pub all_loaded: bool,
|
||||
pub asset_infos: Vec<AssetLoadTracker<T>>,
|
||||
pub progress: f32,
|
||||
}
|
||||
impl<T: bevy::prelude::Asset> Default for AssetsToLoad<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
all_loaded: Default::default(),
|
||||
asset_infos: Default::default(),
|
||||
progress: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// flag component, usually added when a blueprint is loaded
|
||||
#[derive(Component)]
|
||||
pub(crate) struct BlueprintAssetsLoaded;
|
||||
/// flag component
|
||||
#[derive(Component)]
|
||||
pub(crate) struct BlueprintAssetsNotLoaded;
|
||||
|
||||
/// spawning prepare function,
|
||||
/// * also takes into account the already exisiting "override" components, ie "override components" > components from blueprint
|
||||
pub(crate) fn prepare_blueprints(
|
||||
spawn_placeholders: Query<
|
||||
(
|
||||
Entity,
|
||||
/*&BlueprintName,
|
||||
&BlueprintPath,
|
||||
Option<&Parent>,*/
|
||||
&BlueprintName,
|
||||
Option<&Parent>,
|
||||
Option<&Library>,
|
||||
Option<&Name>,
|
||||
Option<&BlueprintAssets>,
|
||||
Option<&BlueprintsList>,
|
||||
),
|
||||
(Added<BlueprintAssets>), // Added<BlueprintAssets>
|
||||
(Added<BlueprintName>, Added<SpawnHere>, Without<Spawned>),
|
||||
>,
|
||||
|
||||
bla_bla: Query<
|
||||
(Entity, &BlueprintName, &BlueprintPath, Option<&Parent>),
|
||||
(Added<BlueprintPath>),
|
||||
>,
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
blueprints_config: Res<BluePrintsConfig>,
|
||||
) {
|
||||
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<Gltf> = asset_server.load(model_path.clone());
|
||||
}
|
||||
|
||||
for (entity, blueprint_name, blueprint_path, parent) in bla_bla.iter() {
|
||||
println!(
|
||||
"added blueprint to spawn {:?} {:?}",
|
||||
blueprint_name, blueprint_path
|
||||
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<AssetLoadTracker> = 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<AssetLoadTracker<Gltf>> = vec![];
|
||||
let library_path =
|
||||
library_override.map_or_else(|| &blueprints_config.library_folder, |l| &l.0);
|
||||
for (blueprint_name, _) in blueprints_list.0.iter() {
|
||||
let model_file_name = format!("{}.{}", &blueprint_name, &blueprints_config.format);
|
||||
let model_path = Path::new(&library_path).join(Path::new(model_file_name.as_str()));
|
||||
|
||||
// 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<AssetLoadTracker> = 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<Gltf> = asset_server.load(model_path.clone());
|
||||
let model_id = model_handle.id();
|
||||
let loaded = asset_server.is_loaded_with_dependencies(model_id);
|
||||
if !loaded {
|
||||
asset_infos.push(AssetLoadTracker {
|
||||
name: 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<Gltf>),
|
||||
With<BlueprintAssetsNotLoaded>,
|
||||
>,
|
||||
asset_server: Res<AssetServer>,
|
||||
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::<BlueprintAssetsNotLoaded>()
|
||||
.remove::<AssetsToLoad>();
|
||||
.remove::<BlueprintAssetsNotLoaded>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<Entity, With<GameWorldTag>>,
|
||||
|
||||
assets_gltf: Res<Assets<Gltf>>,
|
||||
mut graphs: ResMut<Assets<AnimationGraph>>,
|
||||
asset_server: Res<AssetServer>,
|
||||
blueprints_config: Res<BluePrintsConfig>,
|
||||
|
||||
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<Gltf> = 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<Gltf> = asset_server.load(model_path.clone()); // FIXME: kinda weird now
|
||||
|
||||
let gltf = assets_gltf.get(&model_handle).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"gltf file {:?} should have been loaded",
|
||||
model_path.to_str()
|
||||
)
|
||||
});
|
||||
|
||||
// WARNING we work under the assumtion that there is ONLY ONE named scene, and that the first one is the right one
|
||||
let main_scene_name = gltf
|
||||
|
@ -286,10 +275,16 @@ pub(crate) fn spawn_from_blueprints2(
|
|||
}
|
||||
}
|
||||
|
||||
let mut graph = AnimationGraph::new();
|
||||
let mut named_animations: HashMap<String, Handle<AnimationClip>> = HashMap::new();
|
||||
for (key, value) in gltf.named_animations.iter() {
|
||||
named_animations.insert(key.to_string(), value.clone());
|
||||
let mut named_indices: HashMap<String, AnimationNodeIndex> = 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() {
|
||||
|
|
|
@ -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::<SpawnHere>();
|
||||
commands.entity(original).remove::<Spawned>();
|
||||
// commands.entity(original).remove::<Handle<Scene>>(); // FIXME: if we delete the handle to the scene, things get despawned ! not what we want
|
||||
//commands.entity(original).remove::<AssetsToLoad>(); // also clear the sub assets tracker to free up handles, perhaps just freeing up the handles and leave the rest would be better ?
|
||||
//commands.entity(original).remove::<BlueprintAssetsLoaded>();
|
||||
commands.entity(original).remove::<Handle<Scene>>();
|
||||
commands.entity(original).remove::<AssetsToLoad<Gltf>>(); // also clear the sub assets tracker to free up handles, perhaps just freeing up the handles and leave the rest would be better ?
|
||||
commands.entity(original).remove::<BlueprintAssetsLoaded>();
|
||||
commands.entity(root_entity).despawn_recursive();
|
||||
info!("DONE WITH POST PROCESS");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"] }
|
||||
bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] }
|
|
@ -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::<f32>().unwrap().to_string();
|
||||
}
|
||||
"f64" => {
|
||||
formated = parsed_value.parse::<f64>().unwrap().to_string();
|
||||
}
|
||||
"u8" => {
|
||||
formated = parsed_value.parse::<u8>().unwrap().to_string();
|
||||
}
|
||||
"u16" => {
|
||||
formated = parsed_value.parse::<u16>().unwrap().to_string();
|
||||
}
|
||||
"u32" => {
|
||||
formated = parsed_value.parse::<u32>().unwrap().to_string();
|
||||
}
|
||||
"u64" => {
|
||||
formated = parsed_value.parse::<u64>().unwrap().to_string();
|
||||
}
|
||||
"u128" => {
|
||||
formated = parsed_value.parse::<u128>().unwrap().to_string();
|
||||
}
|
||||
"glam::Vec2" => {
|
||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||
formated = format!("(x:{},y:{})", parsed[0], parsed[1]);
|
||||
}
|
||||
"glam::Vec3" => {
|
||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||
formated =
|
||||
format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]);
|
||||
}
|
||||
"bevy_render::color::Color" => {
|
||||
let parsed: Vec<f32> = 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` |
|
||||
|
|
|
@ -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<GltfComponentsConfig>) {
|
||||
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::<GltfProcessed>()
|
||||
.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),
|
||||
|
|
|
@ -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<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>>
|
||||
fn find_entity_components(
|
||||
entity: Entity,
|
||||
name: &Name,
|
||||
parent: &Parent,
|
||||
reflect_components: Vec<(Box<dyn Reflect>, TypeRegistration)>,
|
||||
entity_components: &HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>>,
|
||||
) -> (Entity, Vec<(Box<dyn Reflect>, 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<dyn Reflect>, 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<GltfExtras>, Without<GltfProcessed>)>();
|
||||
|
||||
let mut scene_extras = world.query_filtered::<(Entity, &Name, &GltfSceneExtras, &Parent), (Added<GltfSceneExtras>, Without<GltfProcessed>)>();
|
||||
let mut mesh_extras = world.query_filtered::<(Entity, &Name, &GltfMeshExtras, &Parent), (Added<GltfMeshExtras>, Without<GltfProcessed>)>();
|
||||
let mut material_extras = world.query_filtered::<(Entity, &Name, &GltfMaterialExtras, &Parent), (Added<GltfMaterialExtras>, Without<GltfProcessed>)>();
|
||||
|
||||
let mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>> =
|
||||
HashMap::new();
|
||||
|
||||
// let gltf_components_config = world.resource::<GltfComponentsConfig>();
|
||||
let gltf_components_config = world.resource::<GltfComponentsConfig>();
|
||||
|
||||
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<dyn Reflect>, 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 {
|
||||
|
|
|
@ -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<dyn Reflect>, TypeRegistration)> {
|
||||
let lookup: HashMap<String, Value> = ron::from_str(ron_string).unwrap();
|
||||
let mut components: Vec<(Box<dyn Reflect>, 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<dyn Reflect>, 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<dyn Reflect>, TypeRegistration)>,
|
||||
) {
|
||||
let lookup: HashMap<String, Value> = 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::<f32>().unwrap().to_string();
|
||||
}
|
||||
"f64" => {
|
||||
formated = parsed_value.parse::<f64>().unwrap().to_string();
|
||||
}
|
||||
"u8" => {
|
||||
formated = parsed_value.parse::<u8>().unwrap().to_string();
|
||||
}
|
||||
"u16" => {
|
||||
formated = parsed_value.parse::<u16>().unwrap().to_string();
|
||||
}
|
||||
"u32" => {
|
||||
formated = parsed_value.parse::<u32>().unwrap().to_string();
|
||||
}
|
||||
"u64" => {
|
||||
formated = parsed_value.parse::<u64>().unwrap().to_string();
|
||||
}
|
||||
"u128" => {
|
||||
formated = parsed_value.parse::<u128>().unwrap().to_string();
|
||||
}
|
||||
"glam::Vec2" => {
|
||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||
formated = format!("(x:{},y:{})", parsed[0], parsed[1]);
|
||||
}
|
||||
"glam::Vec3" => {
|
||||
let parsed: Vec<f32> = ron::from_str(&parsed_value).unwrap();
|
||||
formated =
|
||||
format!("(x:{},y:{},z:{})", parsed[0], parsed[1], parsed[2]);
|
||||
}
|
||||
"bevy_render::color::Color" => {
|
||||
let parsed: Vec<f32> = 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
|
||||
}
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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` |
|
||||
|
|
|
@ -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"] }
|
||||
bevy = { version = "0.14", default-features = false, features = ["dynamic_linking"] }
|
|
@ -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` |
|
||||
|
|
|
@ -17,28 +17,18 @@ pub fn export_types(world: &mut World) {
|
|||
|
||||
let asset_root = world.resource::<AssetRoot>();
|
||||
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::<AppTypeRegistry>();
|
||||
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::<Map<_, _>>();
|
||||
let schemas = types.iter().map(export_type).collect::<Map<_, _>>();
|
||||
|
||||
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::<Map<_, _>>(),
|
||||
"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::<Vec<_>>();
|
||||
|
@ -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",
|
||||
}),
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -354,12 +354,12 @@ pub(crate) fn blueprints_assets_loaded(
|
|||
// prepare data for animations
|
||||
let mut graph = AnimationGraph::new();
|
||||
let mut named_animations: HashMap<String, Handle<AnimationClip>> = HashMap::new();
|
||||
let mut animation_indices: HashMap<String, AnimationNodeIndex> = HashMap::new();
|
||||
let mut named_indices: HashMap<String, AnimationNodeIndex> = 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,
|
||||
},
|
||||
));
|
||||
|
|
|
@ -15,7 +15,7 @@ pub fn setup_game(
|
|||
) {
|
||||
// here we actually spawn our game world/level
|
||||
commands.spawn((
|
||||
BlueprintInfo::from_path("levels/World.gltf"),
|
||||
BlueprintInfo::from_path("levels/World.glb"),
|
||||
HideUntilReady,
|
||||
SpawnBlueprint,
|
||||
GameWorldTag,
|
||||
|
|
|
@ -53,7 +53,7 @@ def test_export_external_blueprints(setup_data):
|
|||
blenvy.auto_export.auto_export = True
|
||||
blenvy.auto_export.export_scene_settings = True
|
||||
blenvy.auto_export.export_blueprints = True
|
||||
blenvy.auto_export.export_materials_library = True
|
||||
#blenvy.auto_export.export_materials_library = True
|
||||
|
||||
print("SCENES", bpy.data.scenes)
|
||||
for scene in bpy.data.scenes:
|
||||
|
|
|
@ -123,9 +123,10 @@ def test_export_complex(setup_data):
|
|||
user_asset.path = "audio/fake.mp3"'''
|
||||
|
||||
# we have to cheat, since we cannot rely on the data injected when saving the library file (since we are not saving it as part of the tests)
|
||||
'''bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb"
|
||||
bpy.data.collections["External_blueprint"]["export_path"] = "blueprints/External_blueprint.glb"
|
||||
bpy.data.collections["External_blueprint2"]["export_path"] = "blueprints/External_blueprint2.glb"
|
||||
bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb"'''
|
||||
bpy.data.collections["External_blueprint3"]["export_path"] = "blueprints/External_blueprint3.glb"
|
||||
#materials/testing_library_materials.glb
|
||||
|
||||
# do the actual exporting
|
||||
prepare_and_export()
|
||||
|
|
Loading…
Reference in New Issue