mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-22 11:50:53 +00:00
chore(crates): updated code from main to v0.14 compatibility for all old crates
This commit is contained in:
parent
3a8844b7a1
commit
a618e0035e
@ -15,7 +15,7 @@ workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_gltf_components = { version = "0.6", path = "../bevy_gltf_components" }
|
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]
|
[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)
|
[![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 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.
|
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
|
* just a Gltf file with Gltf_extras specifying components
|
||||||
* a component called BlueprintName
|
* 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
|
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
|
||||||
- [blenvy](https://github.com/kaosat-dev/Blender_bevy_components_workflow/tree/main/tools/blenvy)
|
- [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
|
## Usage
|
||||||
@ -26,8 +29,8 @@ Here's a minimal usage example:
|
|||||||
```toml
|
```toml
|
||||||
# Cargo.toml
|
# Cargo.toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy="0.13"
|
bevy="0.14"
|
||||||
bevy_gltf_blueprints = { version = "0.10"}
|
bevy_gltf_blueprints = { version = "0.11.0"}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -65,7 +68,7 @@ fn spawn_blueprint(
|
|||||||
Add the following to your `[dependencies]` section in `Cargo.toml`:
|
Add the following to your `[dependencies]` section in `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
bevy_gltf_blueprints = "0.10"
|
bevy_gltf_blueprints = "0.11.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
Or use `cargo add`:
|
Or use `cargo add`:
|
||||||
@ -100,8 +103,11 @@ fn main() {
|
|||||||
App::new()
|
App::new()
|
||||||
.add_plugins((
|
.add_plugins((
|
||||||
BlueprintsPlugin{
|
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
|
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: 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()
|
..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***
|
***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
|
## 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:
|
you can configure this with the settings:
|
||||||
```rust
|
```rust
|
||||||
material_library: true // defaults to false, enable this to enable automatic injection of materials from material library files
|
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
|
> 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
|
```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)
|
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
|
## 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
|
## 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:
|
Compatibility of `bevy_gltf_blueprints` versions:
|
||||||
| `bevy_gltf_blueprints` | `bevy` |
|
| `bevy_gltf_blueprints` | `bevy` |
|
||||||
| :-- | :-- |
|
| :-- | :-- |
|
||||||
|
| `0.11` | `0.14` |
|
||||||
| `0.9 - 0.10` | `0.13` |
|
| `0.9 - 0.10` | `0.13` |
|
||||||
| `0.3 - 0.8` | `0.12` |
|
| `0.3 - 0.8` | `0.12` |
|
||||||
| `0.1 - 0.2` | `0.11` |
|
| `0.1 - 0.2` | `0.11` |
|
||||||
|
@ -3,9 +3,11 @@ use bevy::utils::HashMap;
|
|||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[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`
|
/// storage for animations for a given entity (hierarchy), essentially a clone of gltf's `named_animations`
|
||||||
pub struct BlueprintAnimations {
|
pub struct Animations {
|
||||||
pub named_animations: HashMap<String, Handle<AnimationClip>>,
|
pub named_animations: HashMap<String, Handle<AnimationClip>>,
|
||||||
|
pub named_indices: HashMap<String, AnimationNodeIndex>,
|
||||||
|
pub graph: Handle<AnimationGraph>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Debug)]
|
#[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
|
/// 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"
|
/// 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
|
/// ie armature/root for animated models, which means more complex queries to trigger animations that we want to avoid
|
||||||
pub struct BlueprintAnimationPlayerLink(pub Entity);
|
pub struct AnimationPlayerLink(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use bevy::ecs::world::Command;
|
use bevy::{ecs::world::Command, prelude::*};
|
||||||
use bevy::prelude::*;
|
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
// originally based https://github.com/bevyengine/bevy/issues/1515,
|
// originally based https://github.com/bevyengine/bevy/issues/1515,
|
||||||
|
@ -10,9 +10,6 @@ pub use animation::*;
|
|||||||
pub mod aabb;
|
pub mod aabb;
|
||||||
pub use aabb::*;
|
pub use aabb::*;
|
||||||
|
|
||||||
pub mod assets;
|
|
||||||
pub use assets::*;
|
|
||||||
|
|
||||||
pub mod materials;
|
pub mod materials;
|
||||||
pub use materials::*;
|
pub use materials::*;
|
||||||
|
|
||||||
@ -22,7 +19,11 @@ pub use copy_components::*;
|
|||||||
use core::fmt;
|
use core::fmt;
|
||||||
use std::path::PathBuf;
|
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};
|
use bevy_gltf_components::{ComponentsFromGltfPlugin, GltfComponentsSet};
|
||||||
|
|
||||||
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
|
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
|
||||||
@ -35,14 +36,12 @@ pub enum GltfBlueprintsSet {
|
|||||||
#[derive(Bundle)]
|
#[derive(Bundle)]
|
||||||
pub struct BluePrintBundle {
|
pub struct BluePrintBundle {
|
||||||
pub blueprint: BlueprintName,
|
pub blueprint: BlueprintName,
|
||||||
pub blueprint_path: BlueprintPath,
|
|
||||||
pub spawn_here: SpawnHere,
|
pub spawn_here: SpawnHere,
|
||||||
}
|
}
|
||||||
impl Default for BluePrintBundle {
|
impl Default for BluePrintBundle {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
BluePrintBundle {
|
BluePrintBundle {
|
||||||
blueprint: BlueprintName("default".into()),
|
blueprint: BlueprintName("default".into()),
|
||||||
blueprint_path: BlueprintPath("".into()),
|
|
||||||
spawn_here: SpawnHere,
|
spawn_here: SpawnHere,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,10 +49,13 @@ impl Default for BluePrintBundle {
|
|||||||
|
|
||||||
#[derive(Clone, Resource)]
|
#[derive(Clone, Resource)]
|
||||||
pub struct BluePrintsConfig {
|
pub struct BluePrintsConfig {
|
||||||
|
pub(crate) format: GltfFormat,
|
||||||
|
pub(crate) library_folder: PathBuf,
|
||||||
pub(crate) aabbs: bool,
|
pub(crate) aabbs: bool,
|
||||||
pub(crate) aabb_cache: HashMap<String, Aabb>, // cache for aabbs
|
pub(crate) aabb_cache: HashMap<String, Aabb>, // cache for aabbs
|
||||||
|
|
||||||
pub(crate) material_library: bool,
|
pub(crate) material_library: bool,
|
||||||
|
pub(crate) material_library_folder: PathBuf,
|
||||||
pub(crate) material_library_cache: HashMap<String, Handle<StandardMaterial>>,
|
pub(crate) material_library_cache: HashMap<String, Handle<StandardMaterial>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,17 +82,27 @@ impl fmt::Display for GltfFormat {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
/// Plugin for gltf blueprints
|
/// Plugin for gltf blueprints
|
||||||
pub struct BlueprintsPlugin {
|
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
|
/// Automatically generate aabbs for the blueprints root objects
|
||||||
pub aabbs: bool,
|
pub aabbs: bool,
|
||||||
///
|
///
|
||||||
pub material_library: bool,
|
pub material_library: bool,
|
||||||
|
pub material_library_folder: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BlueprintsPlugin {
|
impl Default for BlueprintsPlugin {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
legacy_mode: true,
|
||||||
|
format: GltfFormat::GLB,
|
||||||
|
library_folder: PathBuf::from("models/library"),
|
||||||
aabbs: false,
|
aabbs: false,
|
||||||
material_library: 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 {
|
impl Plugin for BlueprintsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_plugins(ComponentsFromGltfPlugin {})
|
app.add_plugins(ComponentsFromGltfPlugin {
|
||||||
.register_type::<BlueprintName>()
|
legacy_mode: self.legacy_mode,
|
||||||
.register_type::<BlueprintPath>()
|
})
|
||||||
.register_type::<MaterialInfo>()
|
.register_type::<BlueprintName>()
|
||||||
.register_type::<SpawnHere>()
|
.register_type::<MaterialInfo>()
|
||||||
.register_type::<BlueprintAnimations>()
|
.register_type::<SpawnHere>()
|
||||||
.register_type::<SceneAnimations>()
|
.register_type::<Animations>()
|
||||||
.register_type::<AnimationInfo>()
|
.register_type::<BlueprintsList>()
|
||||||
.register_type::<AnimationInfos>()
|
.register_type::<Vec<String>>()
|
||||||
.register_type::<Vec<AnimationInfo>>()
|
.register_type::<HashMap<String, Vec<String>>>()
|
||||||
.register_type::<AnimationMarkers>()
|
.insert_resource(BluePrintsConfig {
|
||||||
.register_type::<HashMap<u32, Vec<String>>>()
|
format: self.format,
|
||||||
.register_type::<HashMap<String, HashMap<u32, Vec<String>>>>()
|
library_folder: self.library_folder.clone(),
|
||||||
.add_event::<AnimationMarkerReached>()
|
|
||||||
.register_type::<BlueprintAsset>()
|
|
||||||
.register_type::<Vec<BlueprintAsset>>()
|
|
||||||
.register_type::<Vec<String>>()
|
|
||||||
.register_type::<LocalAssets>()
|
|
||||||
.register_type::<BlueprintAssets>()
|
|
||||||
|
|
||||||
|
aabbs: self.aabbs,
|
||||||
|
aabb_cache: HashMap::new(),
|
||||||
|
|
||||||
.register_type::<HashMap<String, Vec<String>>>()
|
material_library: self.material_library,
|
||||||
.insert_resource(BluePrintsConfig {
|
material_library_folder: self.material_library_folder.clone(),
|
||||||
|
material_library_cache: HashMap::new(),
|
||||||
aabbs: self.aabbs,
|
})
|
||||||
aabb_cache: HashMap::new(),
|
.configure_sets(
|
||||||
|
Update,
|
||||||
material_library: self.material_library,
|
(GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn)
|
||||||
material_library_cache: HashMap::new(),
|
.chain()
|
||||||
})
|
.after(GltfComponentsSet::Injection),
|
||||||
.configure_sets(
|
)
|
||||||
Update,
|
.add_systems(
|
||||||
(GltfBlueprintsSet::Spawn, GltfBlueprintsSet::AfterSpawn)
|
Update,
|
||||||
.chain()
|
(
|
||||||
.after(GltfComponentsSet::Injection),
|
|
||||||
)
|
|
||||||
.add_systems(
|
|
||||||
Update,
|
|
||||||
(
|
(
|
||||||
test_thingy,
|
prepare_blueprints,
|
||||||
check_for_loaded2,
|
check_for_loaded,
|
||||||
spawn_from_blueprints2,
|
spawn_from_blueprints,
|
||||||
|
|
||||||
/*(
|
|
||||||
prepare_blueprints,
|
|
||||||
check_for_loaded,
|
|
||||||
spawn_from_blueprints,
|
|
||||||
apply_deferred,
|
|
||||||
)
|
|
||||||
.chain(),*/
|
|
||||||
(compute_scene_aabbs, apply_deferred)
|
|
||||||
.chain()
|
|
||||||
.run_if(aabbs_enabled),
|
|
||||||
apply_deferred,
|
apply_deferred,
|
||||||
(
|
)
|
||||||
materials_inject,
|
.chain(),
|
||||||
check_for_material_loaded,
|
(compute_scene_aabbs, apply_deferred)
|
||||||
materials_inject2,
|
.chain()
|
||||||
)
|
.run_if(aabbs_enabled),
|
||||||
.chain()
|
apply_deferred,
|
||||||
.run_if(materials_library_enabled),
|
(
|
||||||
|
materials_inject,
|
||||||
|
check_for_material_loaded,
|
||||||
|
materials_inject2,
|
||||||
)
|
)
|
||||||
.chain()
|
.chain()
|
||||||
.in_set(GltfBlueprintsSet::Spawn),
|
.run_if(materials_library_enabled),
|
||||||
)
|
)
|
||||||
.add_systems(
|
.chain()
|
||||||
Update,
|
.in_set(GltfBlueprintsSet::Spawn),
|
||||||
(spawned_blueprint_post_process, apply_deferred)
|
)
|
||||||
.chain()
|
.add_systems(
|
||||||
.in_set(GltfBlueprintsSet::AfterSpawn),
|
PostUpdate,
|
||||||
)
|
(spawned_blueprint_post_process, apply_deferred)
|
||||||
/* .add_systems(
|
.chain()
|
||||||
Update,
|
.in_set(GltfBlueprintsSet::AfterSpawn)
|
||||||
(
|
.before(VisibilitySystems::CheckVisibility),
|
||||||
trigger_instance_animation_markers_events,
|
);
|
||||||
trigger_blueprint_animation_markers_events,
|
|
||||||
),
|
|
||||||
)*/
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,14 +17,14 @@ use bevy::{
|
|||||||
render::mesh::Mesh,
|
render::mesh::Mesh,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{AssetLoadTracker, AssetsToLoad, BluePrintsConfig, BlueprintInstanceReady};
|
use crate::{AssetLoadTracker, AssetsToLoad, BluePrintsConfig};
|
||||||
|
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[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 struct MaterialInfo {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub path: String,
|
pub source: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// flag component
|
/// flag component
|
||||||
@ -42,8 +42,15 @@ pub(crate) fn materials_inject(
|
|||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for (entity, material_info) in material_infos.iter() {
|
for (entity, material_info) in material_infos.iter() {
|
||||||
println!("Entity with material info {:?} {:?}", entity, material_info);
|
let model_file_name = format!(
|
||||||
let material_full_path = format!("{}#{}", material_info.path, material_info.name);
|
"{}_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
|
if blueprints_config
|
||||||
.material_library_cache
|
.material_library_cache
|
||||||
.contains_key(&material_full_path)
|
.contains_key(&material_full_path)
|
||||||
@ -57,11 +64,10 @@ pub(crate) fn materials_inject(
|
|||||||
.entity(entity)
|
.entity(entity)
|
||||||
.insert(BlueprintMaterialAssetsLoaded);
|
.insert(BlueprintMaterialAssetsLoaded);
|
||||||
} else {
|
} 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 material_file_id = material_file_handle.id();
|
||||||
|
let asset_infos: Vec<AssetLoadTracker<Gltf>> = vec![AssetLoadTracker {
|
||||||
let asset_infos: Vec<AssetLoadTracker> = vec![AssetLoadTracker {
|
name: material_full_path,
|
||||||
name: material_info.name.clone(),
|
|
||||||
id: material_file_id,
|
id: material_file_id,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
handle: material_file_handle.clone(),
|
handle: material_file_handle.clone(),
|
||||||
@ -75,6 +81,7 @@ pub(crate) fn materials_inject(
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.insert(BlueprintMaterialAssetsNotLoaded);
|
.insert(BlueprintMaterialAssetsNotLoaded);
|
||||||
|
/**/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +89,7 @@ pub(crate) fn materials_inject(
|
|||||||
// TODO, merge with check_for_loaded, make generic ?
|
// TODO, merge with check_for_loaded, make generic ?
|
||||||
pub(crate) fn check_for_material_loaded(
|
pub(crate) fn check_for_material_loaded(
|
||||||
mut blueprint_assets_to_load: Query<
|
mut blueprint_assets_to_load: Query<
|
||||||
(Entity, &mut AssetsToLoad),
|
(Entity, &mut AssetsToLoad<Gltf>),
|
||||||
With<BlueprintMaterialAssetsNotLoaded>,
|
With<BlueprintMaterialAssetsNotLoaded>,
|
||||||
>,
|
>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
@ -139,7 +146,15 @@ pub(crate) fn materials_inject2(
|
|||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for (material_info, children) in material_infos.iter() {
|
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;
|
let mut material_found: Option<&Handle<StandardMaterial>> = None;
|
||||||
|
|
||||||
if blueprints_config
|
if blueprints_config
|
||||||
@ -153,17 +168,14 @@ pub(crate) fn materials_inject2(
|
|||||||
.expect("we should have the material available");
|
.expect("we should have the material available");
|
||||||
material_found = Some(material);
|
material_found = Some(material);
|
||||||
} else {
|
} else {
|
||||||
let model_handle: Handle<Gltf> = asset_server.load(material_info.path.clone()); // FIXME: kinda weird now
|
let model_handle: Handle<Gltf> = asset_server.load(materials_path.clone()); // FIXME: kinda weird now
|
||||||
let mat_gltf = assets_gltf
|
let mat_gltf = assets_gltf
|
||||||
.get(model_handle.id())
|
.get(model_handle.id())
|
||||||
.expect("material should have been preloaded");
|
.expect("material should have been preloaded");
|
||||||
if mat_gltf
|
if mat_gltf.named_materials.contains_key(material_name as &str) {
|
||||||
.named_materials
|
|
||||||
.contains_key(&material_info.name as &str)
|
|
||||||
{
|
|
||||||
let material = mat_gltf
|
let material = mat_gltf
|
||||||
.named_materials
|
.named_materials
|
||||||
.get(&material_info.name as &str)
|
.get(material_name as &str)
|
||||||
.expect("this material should have been loaded");
|
.expect("this material should have been loaded");
|
||||||
blueprints_config
|
blueprints_config
|
||||||
.material_library_cache
|
.material_library_cache
|
||||||
@ -177,8 +189,8 @@ pub(crate) fn materials_inject2(
|
|||||||
if with_materials_and_meshes.contains(*child) {
|
if with_materials_and_meshes.contains(*child) {
|
||||||
debug!(
|
debug!(
|
||||||
"injecting material {}, path: {:?}",
|
"injecting material {}, path: {:?}",
|
||||||
material_info.name,
|
material_name,
|
||||||
material_info.path.clone()
|
materials_path.clone()
|
||||||
);
|
);
|
||||||
|
|
||||||
commands.entity(*child).insert(material.clone());
|
commands.entity(*child).insert(material.clone());
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use bevy::{gltf::Gltf, prelude::*, utils::hashbrown::HashMap};
|
use bevy::{gltf::Gltf, prelude::*, utils::HashMap};
|
||||||
|
|
||||||
use crate::{
|
use crate::{Animations, BluePrintsConfig};
|
||||||
AssetLoadTracker, AssetsToLoad, BluePrintsConfig, BlueprintAnimations, BlueprintAssets,
|
|
||||||
BlueprintAssetsLoaded, BlueprintAssetsNotLoaded,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// this is a flag component for our levels/game world
|
/// this is a flag component for our levels/game world
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
@ -16,11 +13,6 @@ pub struct GameWorldTag;
|
|||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct BlueprintName(pub String);
|
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
|
/// flag component needed to signify the intent to spawn a Blueprint
|
||||||
#[derive(Component, Reflect, Default, Debug)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
@ -30,12 +22,6 @@ pub struct SpawnHere;
|
|||||||
/// flag component for dynamically spawned scenes
|
/// flag component for dynamically spawned scenes
|
||||||
pub struct Spawned;
|
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)]
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
/// flag component marking any spwaned child of blueprints ..unless the original entity was marked with the `NoInBlueprint` marker 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
|
/// helper component, just to transfer child data
|
||||||
pub(crate) struct OriginalChildren(pub Vec<Entity>);
|
pub(crate) struct OriginalChildren(pub Vec<Entity>);
|
||||||
|
|
||||||
pub(crate) fn test_thingy(
|
/// helper component, is used to store the list of sub blueprints to enable automatic loading of dependend blueprints
|
||||||
spawn_placeholders: Query<
|
#[derive(Component, Reflect, Default, Debug)]
|
||||||
(Entity, &BlueprintPath),
|
#[reflect(Component)]
|
||||||
(Added<BlueprintPath>, Without<Spawned>, Without<SpawnHere>),
|
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
|
/// helper component, for tracking loaded assets's loading state, id , handle etc
|
||||||
entities_with_assets: Query<
|
#[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,
|
Entity,
|
||||||
/*&BlueprintName,
|
&BlueprintName,
|
||||||
&BlueprintPath,
|
Option<&Parent>,
|
||||||
Option<&Parent>,*/
|
Option<&Library>,
|
||||||
Option<&Name>,
|
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,
|
mut commands: Commands,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
|
blueprints_config: Res<BluePrintsConfig>,
|
||||||
) {
|
) {
|
||||||
for (entity, blueprint_path) in spawn_placeholders.iter() {
|
for (entity, blupeprint_name, original_parent, library_override, name, blueprints_list) in
|
||||||
//println!("added blueprint_path {:?}", blueprint_path);
|
spawn_placeholders.iter()
|
||||||
/*commands.entity(entity).insert(
|
{
|
||||||
SceneBundle {
|
debug!(
|
||||||
scene: asset_server.load(format!("{}#Scene0", &blueprint_path.0)), // "levels/World.glb#Scene0"),
|
"requesting to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}",
|
||||||
..default()
|
blupeprint_name.0, name, entity, original_parent
|
||||||
},
|
|
||||||
);*/
|
|
||||||
// let model_handle: Handle<Gltf> = asset_server.load(model_path.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (entity, blueprint_name, blueprint_path, parent) in bla_bla.iter() {
|
|
||||||
println!(
|
|
||||||
"added blueprint to spawn {:?} {:?}",
|
|
||||||
blueprint_name, blueprint_path
|
|
||||||
);
|
);
|
||||||
let untyped_handle = asset_server.load_untyped(&blueprint_path.0);
|
|
||||||
let asset_id = untyped_handle.id();
|
|
||||||
let loaded = asset_server.is_loaded_with_dependencies(asset_id);
|
|
||||||
|
|
||||||
let mut asset_infos: Vec<AssetLoadTracker> = vec![];
|
// println!("main model path {:?}", model_path);
|
||||||
if !loaded {
|
if blueprints_list.is_some() {
|
||||||
asset_infos.push(AssetLoadTracker {
|
let blueprints_list = blueprints_list.unwrap();
|
||||||
name: blueprint_name.0.clone(),
|
// println!("blueprints list {:?}", blueprints_list.0.keys());
|
||||||
id: asset_id,
|
let mut asset_infos: Vec<AssetLoadTracker<Gltf>> = vec![];
|
||||||
loaded: false,
|
let library_path =
|
||||||
handle: untyped_handle.clone(),
|
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
|
let model_handle: Handle<Gltf> = asset_server.load(model_path.clone());
|
||||||
if !asset_infos.is_empty() {
|
let model_id = model_handle.id();
|
||||||
commands
|
let loaded = asset_server.is_loaded_with_dependencies(model_id);
|
||||||
.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);
|
|
||||||
if !loaded {
|
if !loaded {
|
||||||
asset_infos.push(AssetLoadTracker {
|
asset_infos.push(AssetLoadTracker {
|
||||||
name: asset.name.clone(),
|
name: model_path.to_string_lossy().into(),
|
||||||
id: asset_id,
|
id: model_id,
|
||||||
loaded: false,
|
loaded: false,
|
||||||
handle: untyped_handle.clone(),
|
handle: model_handle.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if not all assets are already loaded, inject a component to signal that we need them to be loaded
|
||||||
// now insert load tracker
|
|
||||||
if !asset_infos.is_empty() {
|
if !asset_infos.is_empty() {
|
||||||
commands
|
commands
|
||||||
.entity(child_entity)
|
.entity(entity)
|
||||||
.insert(AssetsToLoad {
|
.insert(AssetsToLoad {
|
||||||
all_loaded: false,
|
all_loaded: false,
|
||||||
asset_infos,
|
asset_infos,
|
||||||
@ -166,70 +147,59 @@ pub(crate) fn test_thingy(
|
|||||||
})
|
})
|
||||||
.insert(BlueprintAssetsNotLoaded);
|
.insert(BlueprintAssetsNotLoaded);
|
||||||
} else {
|
} 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<
|
mut blueprint_assets_to_load: Query<
|
||||||
(Entity, Option<&Name>, &mut AssetsToLoad),
|
(Entity, &mut AssetsToLoad<Gltf>),
|
||||||
With<BlueprintAssetsNotLoaded>,
|
With<BlueprintAssetsNotLoaded>,
|
||||||
>,
|
>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
mut commands: Commands,
|
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 all_loaded = true;
|
||||||
let mut loaded_amount = 0;
|
let mut loaded_amount = 0;
|
||||||
let total = assets_to_load.asset_infos.len();
|
let total = assets_to_load.asset_infos.len();
|
||||||
for tracker in assets_to_load.asset_infos.iter_mut() {
|
for tracker in assets_to_load.asset_infos.iter_mut() {
|
||||||
let asset_id = tracker.id;
|
let asset_id = tracker.id;
|
||||||
let loaded = asset_server.is_loaded_with_dependencies(asset_id);
|
let loaded = asset_server.is_loaded_with_dependencies(asset_id);
|
||||||
println!(
|
tracker.loaded = loaded;
|
||||||
"loading {}: // load state: {:?}",
|
if loaded {
|
||||||
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 {
|
|
||||||
loaded_amount += 1;
|
loaded_amount += 1;
|
||||||
} else {
|
} else {
|
||||||
all_loaded = false;
|
all_loaded = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let progress: f32 = loaded_amount as f32 / total as f32;
|
let progress: f32 = loaded_amount as f32 / total as f32;
|
||||||
println!("progress: {}", progress);
|
// println!("progress: {}",progress);
|
||||||
assets_to_load.progress = progress;
|
assets_to_load.progress = progress;
|
||||||
|
|
||||||
if all_loaded {
|
if all_loaded {
|
||||||
assets_to_load.all_loaded = true;
|
assets_to_load.all_loaded = true;
|
||||||
println!("done with loading {:?}, inserting components", entity_name);
|
|
||||||
commands
|
commands
|
||||||
.entity(entity)
|
.entity(entity)
|
||||||
.insert(BlueprintAssetsLoaded)
|
.insert(BlueprintAssetsLoaded)
|
||||||
.remove::<BlueprintAssetsNotLoaded>()
|
.remove::<BlueprintAssetsNotLoaded>();
|
||||||
.remove::<AssetsToLoad>();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn spawn_from_blueprints2(
|
pub(crate) fn spawn_from_blueprints(
|
||||||
spawn_placeholders: Query<
|
spawn_placeholders: Query<
|
||||||
(
|
(
|
||||||
Entity,
|
Entity,
|
||||||
&BlueprintName,
|
&BlueprintName,
|
||||||
&BlueprintPath,
|
|
||||||
Option<&Transform>,
|
Option<&Transform>,
|
||||||
Option<&Parent>,
|
Option<&Parent>,
|
||||||
|
Option<&Library>,
|
||||||
Option<&AddToGameWorld>,
|
Option<&AddToGameWorld>,
|
||||||
Option<&Name>,
|
Option<&Name>,
|
||||||
),
|
),
|
||||||
@ -244,25 +214,44 @@ pub(crate) fn spawn_from_blueprints2(
|
|||||||
mut game_world: Query<Entity, With<GameWorldTag>>,
|
mut game_world: Query<Entity, With<GameWorldTag>>,
|
||||||
|
|
||||||
assets_gltf: Res<Assets<Gltf>>,
|
assets_gltf: Res<Assets<Gltf>>,
|
||||||
|
mut graphs: ResMut<Assets<AnimationGraph>>,
|
||||||
asset_server: Res<AssetServer>,
|
asset_server: Res<AssetServer>,
|
||||||
blueprints_config: Res<BluePrintsConfig>,
|
blueprints_config: Res<BluePrintsConfig>,
|
||||||
|
|
||||||
children: Query<&Children>,
|
children: Query<&Children>,
|
||||||
) {
|
) {
|
||||||
for (entity, blupeprint_name, blueprint_path, transform, original_parent, add_to_world, name) in
|
for (
|
||||||
spawn_placeholders.iter()
|
entity,
|
||||||
|
blupeprint_name,
|
||||||
|
transform,
|
||||||
|
original_parent,
|
||||||
|
library_override,
|
||||||
|
add_to_world,
|
||||||
|
name,
|
||||||
|
) in spawn_placeholders.iter()
|
||||||
{
|
{
|
||||||
info!(
|
debug!(
|
||||||
"attempting to spawn blueprint {:?} for entity {:?}, id: {:?}, parent:{:?}",
|
"attempting to spawn {:?} for entity {:?}, id: {:?}, parent:{:?}",
|
||||||
blupeprint_name.0, name, entity, original_parent
|
blupeprint_name.0, name, entity, original_parent
|
||||||
);
|
);
|
||||||
|
|
||||||
// info!("attempting to spawn {:?}", model_path);
|
let what = &blupeprint_name.0;
|
||||||
let model_handle: Handle<Gltf> = asset_server.load(blueprint_path.0.clone()); // FIXME: kinda weird now
|
let model_file_name = format!("{}.{}", &what, &blueprints_config.format);
|
||||||
|
|
||||||
let gltf = assets_gltf
|
// library path is either defined at the plugin level or overriden by optional Library components
|
||||||
.get(&model_handle)
|
let library_path =
|
||||||
.unwrap_or_else(|| panic!("gltf file {:?} should have been loaded", &blueprint_path.0));
|
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
|
// 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
|
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();
|
let mut named_animations: HashMap<String, Handle<AnimationClip>> = HashMap::new();
|
||||||
for (key, value) in gltf.named_animations.iter() {
|
let mut named_indices: HashMap<String, AnimationNodeIndex> = HashMap::new();
|
||||||
named_animations.insert(key.to_string(), value.clone());
|
|
||||||
|
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((
|
commands.entity(entity).insert((
|
||||||
SceneBundle {
|
SceneBundle {
|
||||||
@ -297,13 +292,13 @@ pub(crate) fn spawn_from_blueprints2(
|
|||||||
transform: transforms,
|
transform: transforms,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Spawned,
|
Animations {
|
||||||
BlueprintInstanceReady, // FIXME: not sure if this is should be added here or in the post process
|
named_animations,
|
||||||
OriginalChildren(original_children),
|
named_indices,
|
||||||
BlueprintAnimations {
|
graph
|
||||||
// these are animations specific to the inside of the blueprint
|
|
||||||
named_animations: named_animations, //gltf.named_animations.clone(),
|
|
||||||
},
|
},
|
||||||
|
Spawned,
|
||||||
|
OriginalChildren(original_children),
|
||||||
));
|
));
|
||||||
|
|
||||||
if add_to_world.is_some() {
|
if add_to_world.is_some() {
|
||||||
|
@ -5,7 +5,7 @@ use bevy::prelude::*;
|
|||||||
use bevy::scene::SceneInstance;
|
use bevy::scene::SceneInstance;
|
||||||
// use bevy::utils::hashbrown::HashSet;
|
// use bevy::utils::hashbrown::HashSet;
|
||||||
|
|
||||||
use super::{BlueprintAnimationPlayerLink, BlueprintAnimations};
|
use super::{AnimationPlayerLink, Animations};
|
||||||
use super::{SpawnHere, Spawned};
|
use super::{SpawnHere, Spawned};
|
||||||
use crate::{
|
use crate::{
|
||||||
AssetsToLoad, BlueprintAssetsLoaded, CopyComponents, InBlueprint, NoInBlueprint,
|
AssetsToLoad, BlueprintAssetsLoaded, CopyComponents, InBlueprint, NoInBlueprint,
|
||||||
@ -24,7 +24,7 @@ pub(crate) fn spawned_blueprint_post_process(
|
|||||||
Entity,
|
Entity,
|
||||||
&Children,
|
&Children,
|
||||||
&OriginalChildren,
|
&OriginalChildren,
|
||||||
&BlueprintAnimations,
|
&Animations,
|
||||||
Option<&NoInBlueprint>,
|
Option<&NoInBlueprint>,
|
||||||
Option<&Name>,
|
Option<&Name>,
|
||||||
),
|
),
|
||||||
@ -38,7 +38,7 @@ pub(crate) fn spawned_blueprint_post_process(
|
|||||||
for (original, children, original_children, animations, no_inblueprint, name) in
|
for (original, children, original_children, animations, no_inblueprint, name) in
|
||||||
unprocessed_entities.iter()
|
unprocessed_entities.iter()
|
||||||
{
|
{
|
||||||
info!("post processing blueprint for entity {:?}", name);
|
debug!("post processing blueprint for entity {:?}", name);
|
||||||
|
|
||||||
if children.len() == 0 {
|
if children.len() == 0 {
|
||||||
warn!("timing issue ! no children found, please restart your bevy app (bug being investigated)");
|
warn!("timing issue ! no children found, please restart your bevy app (bug being investigated)");
|
||||||
@ -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
|
// 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,
|
// 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
|
// BUT we still want to have some marker/control at the root entity level, we add this
|
||||||
commands
|
commands.entity(original).insert(AnimationPlayerLink(added));
|
||||||
.entity(original)
|
|
||||||
.insert(BlueprintAnimationPlayerLink(added));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.entity(original).remove::<SpawnHere>();
|
commands.entity(original).remove::<SpawnHere>();
|
||||||
commands.entity(original).remove::<Spawned>();
|
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::<Handle<Scene>>();
|
||||||
//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::<AssetsToLoad<Gltf>>(); // also clear the sub assets tracker to free up handles, perhaps just freeing up the handles and leave the rest would be better ?
|
||||||
//commands.entity(original).remove::<BlueprintAssetsLoaded>();
|
commands.entity(original).remove::<BlueprintAssetsLoaded>();
|
||||||
commands.entity(root_entity).despawn_recursive();
|
commands.entity(root_entity).despawn_recursive();
|
||||||
info!("DONE WITH POST PROCESS");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ license = "MIT OR Apache-2.0"
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[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"
|
serde = "1.0.188"
|
||||||
ron = "0.8.1"
|
ron = "0.8.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[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 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.
|
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
|
```toml
|
||||||
# Cargo.toml
|
# Cargo.toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy="0.13"
|
bevy="0.14"
|
||||||
bevy_gltf_components = { version = "0.5"}
|
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`:
|
Add the following to your `[dependencies]` section in `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
bevy_gltf_components = "0.5"
|
bevy_gltf_components = "0.6"
|
||||||
```
|
```
|
||||||
|
|
||||||
Or use `cargo add`:
|
Or use `cargo add`:
|
||||||
@ -78,78 +80,17 @@ Use the default configuration:
|
|||||||
ComponentsFromGltfPlugin::default()
|
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
|
Or disable the legacy mode: (enabled by default)
|
||||||
|
|
||||||
```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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
```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
|
## 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:
|
Compatibility of `bevy_gltf_components` versions:
|
||||||
| `bevy_gltf_components` | `bevy` |
|
| `bevy_gltf_components` | `bevy` |
|
||||||
| :-- | :-- |
|
| :-- | :-- |
|
||||||
|
| `0.6` | `0.14` |
|
||||||
| `0.5` | `0.13` |
|
| `0.5` | `0.13` |
|
||||||
| `0.2 - 0.4` | `0.12` |
|
| `0.2 - 0.4` | `0.12` |
|
||||||
| `0.1` | `0.11` |
|
| `0.1` | `0.11` |
|
||||||
|
@ -10,7 +10,13 @@ pub use process_gltfs::*;
|
|||||||
pub mod blender_settings;
|
pub mod blender_settings;
|
||||||
|
|
||||||
use bevy::{
|
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},
|
prelude::{App, IntoSystemConfigs, Plugin, SystemSet, Update},
|
||||||
reflect::Reflect,
|
reflect::Reflect,
|
||||||
};
|
};
|
||||||
@ -60,16 +66,34 @@ pub enum GltfComponentsSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Resource)]
|
#[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 {
|
impl Plugin for ComponentsFromGltfPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_plugins(blender_settings::plugin)
|
app.add_plugins(blender_settings::plugin)
|
||||||
.register_type::<GltfProcessed>()
|
.register_type::<GltfProcessed>()
|
||||||
.insert_resource(GltfComponentsConfig {})
|
.insert_resource(GltfComponentsConfig {
|
||||||
|
legacy_mode: self.legacy_mode,
|
||||||
|
})
|
||||||
|
.add_systems(Startup, check_for_legacy_mode)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
(add_components_from_gltf_extras).in_set(GltfComponentsSet::Injection),
|
(add_components_from_gltf_extras).in_set(GltfComponentsSet::Injection),
|
||||||
|
@ -6,67 +6,23 @@ use bevy::{
|
|||||||
reflect::{AppTypeRegistry, ReflectComponent},
|
reflect::{AppTypeRegistry, ReflectComponent},
|
||||||
world::World,
|
world::World,
|
||||||
},
|
},
|
||||||
gltf::{GltfExtras, GltfMaterialExtras, GltfMeshExtras, GltfSceneExtras},
|
gltf::GltfExtras,
|
||||||
hierarchy::Parent,
|
hierarchy::Parent,
|
||||||
log::debug,
|
log::debug,
|
||||||
reflect::{Reflect, TypeRegistration},
|
reflect::{Reflect, TypeRegistration},
|
||||||
utils::HashMap,
|
utils::HashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{ronstring_to_reflect_component, GltfProcessed};
|
use crate::{ronstring_to_reflect_component, GltfComponentsConfig, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// main function: injects components into each entity in gltf files that have `gltf_extras`, using reflection
|
/// 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) {
|
pub fn add_components_from_gltf_extras(world: &mut World) {
|
||||||
let mut extras =
|
let mut extras =
|
||||||
world.query_filtered::<(Entity, &Name, &GltfExtras, &Parent), (Added<GltfExtras>, Without<GltfProcessed>)>();
|
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)>> =
|
let mut entity_components: HashMap<Entity, Vec<(Box<dyn Reflect>, TypeRegistration)>> =
|
||||||
HashMap::new();
|
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) {
|
for (entity, name, extra, parent) in extras.iter(world) {
|
||||||
debug!(
|
debug!(
|
||||||
@ -76,56 +32,40 @@ pub fn add_components_from_gltf_extras(world: &mut World) {
|
|||||||
|
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
let type_registry: &AppTypeRegistry = world.resource();
|
||||||
let type_registry = type_registry.read();
|
let type_registry = type_registry.read();
|
||||||
let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry);
|
|
||||||
|
|
||||||
let (target_entity, updated_components) =
|
let reflect_components = ronstring_to_reflect_component(
|
||||||
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
&extra.value,
|
||||||
entity_components.insert(target_entity, updated_components);
|
&type_registry,
|
||||||
}
|
gltf_components_config.legacy_mode,
|
||||||
|
|
||||||
for (entity, name, extra, parent) in scene_extras.iter(world) {
|
|
||||||
debug!(
|
|
||||||
"Name: {}, entity {:?}, parent: {:?}, scene_extras {:?}",
|
|
||||||
name, entity, parent, extra
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
// we assign the components specified /xxx_components objects to their parent node
|
||||||
let type_registry = type_registry.read();
|
let mut target_entity = entity;
|
||||||
let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry);
|
// 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) =
|
// 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
|
||||||
find_entity_components(entity, name, parent, reflect_components, &entity_components);
|
// this allows for example blender collection to provide basic ecs data & the instances to override/ define their own values
|
||||||
entity_components.insert(target_entity, updated_components);
|
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];
|
||||||
for (entity, name, extra, parent) in mesh_extras.iter(world) {
|
// first inject the current components
|
||||||
debug!(
|
for (component, type_registration) in current_components {
|
||||||
"Name: {}, entity {:?}, parent: {:?}, mesh_extras {:?}",
|
updated_components.push((component.clone_value(), type_registration.clone()));
|
||||||
name, entity, parent, extra
|
}
|
||||||
);
|
// then inject the new components: this also enables overwrite components set in the collection
|
||||||
|
for (component, type_registration) in reflect_components {
|
||||||
let type_registry: &AppTypeRegistry = world.resource();
|
updated_components.push((component.clone_value(), type_registration));
|
||||||
let type_registry = type_registry.read();
|
}
|
||||||
let reflect_components = ronstring_to_reflect_component(&extra.value, &type_registry);
|
entity_components.insert(target_entity, updated_components);
|
||||||
|
} else {
|
||||||
let (target_entity, updated_components) =
|
entity_components.insert(target_entity, reflect_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, components) in entity_components {
|
for (entity, components) in entity_components {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use bevy::log::{debug, warn};
|
use bevy::log::{debug, warn};
|
||||||
use bevy::reflect::serde::ReflectDeserializer;
|
use bevy::reflect::serde::ReflectDeserializer;
|
||||||
use bevy::reflect::{Reflect, TypeRegistration, TypeRegistry};
|
use bevy::reflect::{Reflect, TypeInfo, TypeRegistration, TypeRegistry};
|
||||||
use bevy::utils::HashMap;
|
use bevy::utils::HashMap;
|
||||||
use ron::Value;
|
use ron::Value;
|
||||||
use serde::de::DeserializeSeed;
|
use serde::de::DeserializeSeed;
|
||||||
@ -10,102 +10,105 @@ use super::capitalize_first_letter;
|
|||||||
pub fn ronstring_to_reflect_component(
|
pub fn ronstring_to_reflect_component(
|
||||||
ron_string: &str,
|
ron_string: &str,
|
||||||
type_registry: &TypeRegistry,
|
type_registry: &TypeRegistry,
|
||||||
|
simplified_types: bool,
|
||||||
) -> Vec<(Box<dyn Reflect>, TypeRegistration)> {
|
) -> Vec<(Box<dyn Reflect>, TypeRegistration)> {
|
||||||
let lookup: HashMap<String, Value> = ron::from_str(ron_string).unwrap();
|
let lookup: HashMap<String, Value> = ron::from_str(ron_string).unwrap();
|
||||||
let mut components: Vec<(Box<dyn Reflect>, TypeRegistration)> = Vec::new();
|
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() {
|
for (key, value) in lookup.into_iter() {
|
||||||
let parsed_value: String = match value.clone() {
|
let type_string = key.replace("component: ", "").trim().to_string();
|
||||||
Value::String(str) => str,
|
let capitalized_type_name = capitalize_first_letter(type_string.as_str());
|
||||||
_ => ron::to_string(&value).unwrap().to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
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());
|
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!(
|
let ron_string = format!(
|
||||||
"{{ \"{}\":{} }}",
|
"{{ \"{}\":{} }}",
|
||||||
type_registration.type_info().type_path(),
|
type_registration.type_info().type_path(),
|
||||||
parsed_value
|
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);
|
debug!("component data ron string {}", ron_string);
|
||||||
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str())
|
let mut deserializer = ron::Deserializer::from_str(ron_string.as_str())
|
||||||
.expect("deserialzer should have been generated from string");
|
.expect("deserialzer should have been generated from string");
|
||||||
@ -122,9 +125,10 @@ fn bevy_components_string_to_components(
|
|||||||
debug!("component {:?}", component);
|
debug!("component {:?}", component);
|
||||||
debug!("real type {:?}", component.get_represented_type_info());
|
debug!("real type {:?}", component.get_represented_type_info());
|
||||||
components.push((component, type_registration.clone()));
|
components.push((component, type_registration.clone()));
|
||||||
debug!("found type registration for {}", key);
|
debug!("found type registration for {}", capitalized_type_name);
|
||||||
} else {
|
} else {
|
||||||
warn!("no type registration for {}", key);
|
warn!("no type registration for {}", capitalized_type_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
components
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bevy_gltf_save_load"
|
name = "bevy_gltf_save_load"
|
||||||
version = "0.4.1"
|
version = "0.5.0"
|
||||||
authors = ["Mark 'kaosat-dev' Moissette"]
|
authors = ["Mark 'kaosat-dev' Moissette"]
|
||||||
description = "Save & load your bevy games"
|
description = "Save & load your bevy games"
|
||||||
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
||||||
@ -14,8 +14,8 @@ license = "MIT OR Apache-2.0"
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[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" }
|
bevy_gltf_blueprints = { version = "0.11", path = "../bevy_gltf_blueprints" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[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)
|
[![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 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/) .
|
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
|
```toml
|
||||||
# Cargo.toml
|
# Cargo.toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy="0.13"
|
bevy="0.14"
|
||||||
bevy_gltf_save_load = "0.4"
|
bevy_gltf_save_load = "0.5"
|
||||||
bevy_gltf_blueprints = "0.10" // also needed
|
bevy_gltf_blueprints = "0.11" // also needed
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust no_run
|
```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)
|
// 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 {
|
BlueprintsPlugin {
|
||||||
|
library_folder: "models/library".into(),
|
||||||
format: GltfFormat::GLB,
|
format: GltfFormat::GLB,
|
||||||
aabbs: true,
|
aabbs: true,
|
||||||
..Default::default()
|
..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:
|
Compatibility of `bevy_gltf_save_load` versions:
|
||||||
| `bevy_gltf_save_load` | `bevy` |
|
| `bevy_gltf_save_load` | `bevy` |
|
||||||
| :-- | :-- |
|
| :-- | :-- |
|
||||||
|
| `0.5 ` | `0.14` |
|
||||||
| `0.4 ` | `0.13` |
|
| `0.4 ` | `0.13` |
|
||||||
| `0.1 -0.3` | `0.12` |
|
| `0.1 -0.3` | `0.12` |
|
||||||
| branch `main` | `0.12` |
|
| branch `main` | `0.12` |
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bevy_registry_export"
|
name = "bevy_registry_export"
|
||||||
version = "0.3.1"
|
version = "0.4.0"
|
||||||
authors = ["Mark 'kaosat-dev' Moissette", "Pascal 'Killercup' Hertleif"]
|
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"
|
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"
|
homepage = "https://github.com/kaosat-dev/Blender_bevy_components_workflow"
|
||||||
@ -11,11 +11,11 @@ edition = "2021"
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_scene"] }
|
bevy = { version = "0.14", default-features = false, features = ["bevy_scene"] }
|
||||||
bevy_reflect = { version = "0.14.0-rc.3", default-features = false }
|
bevy_reflect = { version = "0.14", default-features = false }
|
||||||
bevy_app = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_reflect"] }
|
bevy_app = { version = "0.14", default-features = false, features = ["bevy_reflect"] }
|
||||||
bevy_ecs = { version = "0.14.0-rc.3", default-features = false, features = ["bevy_reflect"] }
|
bevy_ecs = { version = "0.14", default-features = false, features = ["bevy_reflect"] }
|
||||||
serde_json = "1.0.108"
|
serde_json = "1.0.108"
|
||||||
|
|
||||||
[dev-dependencies]
|
[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)
|
[![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 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.
|
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).
|
(and any of your custom types & components that you register in Bevy).
|
||||||
|
|
||||||
|
|
||||||
@ -17,8 +20,8 @@ Here's a minimal usage example:
|
|||||||
```toml
|
```toml
|
||||||
# Cargo.toml
|
# Cargo.toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy="0.13"
|
bevy="0.14"
|
||||||
bevy_registry_export = "0.3"
|
bevy_registry_export = "0.4"
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust no_run
|
```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`:
|
Add the following to your `[dependencies]` section in `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
bevy_registry_export = "0.3"
|
bevy_registry_export = "0.4"
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -100,6 +103,8 @@ fn main() {
|
|||||||
|
|
||||||
All examples are here:
|
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
|
- 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:
|
Compatibility of `bevy_registry_export` versions:
|
||||||
| `bevy_registry_export` | `bevy` | `bevy_components (Blender add-on)` |
|
| `bevy_registry_export` | `bevy` | `bevy_components (Blender add-on)` |
|
||||||
| :-- | :-- |:-- |
|
| :-- | :-- |:-- |
|
||||||
|
| `0.4 ` | `0.14` | `0.3` |
|
||||||
| `0.3 ` | `0.13` | `0.3` |
|
| `0.3 ` | `0.13` | `0.3` |
|
||||||
| `0.2 ` | `0.12` | `0.3` |
|
| `0.2 ` | `0.12` | `0.3` |
|
||||||
| `0.1 ` | `0.12` | `0.1 -0.2` |
|
| `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 asset_root = world.resource::<AssetRoot>();
|
||||||
let registry_save_path = Path::join(&asset_root.0, &config.save_path);
|
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 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 = world.resource_mut::<AppTypeRegistry>();
|
||||||
let types = types.read();
|
let types = types.read();
|
||||||
let schemas = types
|
let schemas = types.iter().map(export_type).collect::<Map<_, _>>();
|
||||||
.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<_, _>>();
|
|
||||||
|
|
||||||
serde_json::to_writer_pretty(
|
serde_json::to_writer_pretty(
|
||||||
writer,
|
writer,
|
||||||
&json!({
|
&json!({
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"long_name": "bevy component registry schema",
|
"title": "bevy component registry schema",
|
||||||
"$defs": schemas,
|
"$defs": schemas,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@ -67,7 +57,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
json!({
|
json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct",
|
"typeInfo": "Struct",
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"properties": properties,
|
"properties": properties,
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": info
|
"required": info
|
||||||
@ -85,7 +75,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
json!({
|
json!({
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"typeInfo": "Enum",
|
"typeInfo": "Enum",
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"oneOf": info
|
"oneOf": info
|
||||||
.iter()
|
.iter()
|
||||||
.map(|variant| match variant {
|
.map(|variant| match variant {
|
||||||
@ -104,12 +94,12 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
VariantInfo::Struct(v) => json!({
|
VariantInfo::Struct(v) => json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Struct",
|
"typeInfo": "Struct",
|
||||||
"long_name": v.name(),
|
"title": v.name(),
|
||||||
"short_name": v.name().split("::").last().unwrap_or(v.name()),
|
"short_name": v.name().split("::").last().unwrap_or(v.name()),
|
||||||
"properties": v
|
"properties": v
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.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<_, _>>(),
|
.collect::<Map<_, _>>(),
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"required": v
|
"required": v
|
||||||
@ -121,7 +111,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
VariantInfo::Tuple(v) => json!({
|
VariantInfo::Tuple(v) => json!({
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"typeInfo": "Tuple",
|
"typeInfo": "Tuple",
|
||||||
"long_name": v.name(),
|
"title": v.name(),
|
||||||
"short_name":v.name(),
|
"short_name":v.name(),
|
||||||
"prefixItems": v
|
"prefixItems": v
|
||||||
.iter()
|
.iter()
|
||||||
@ -131,7 +121,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
"items": false,
|
"items": false,
|
||||||
}),
|
}),
|
||||||
VariantInfo::Unit(v) => json!({
|
VariantInfo::Unit(v) => json!({
|
||||||
"long_name": v.name(),
|
"title": v.name(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -139,13 +129,13 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
json!({
|
json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Enum",
|
"typeInfo": "Enum",
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"oneOf": variants,
|
"oneOf": variants,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeInfo::TupleStruct(info) => json!({
|
TypeInfo::TupleStruct(info) => json!({
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"typeInfo": "TupleStruct",
|
"typeInfo": "TupleStruct",
|
||||||
"prefixItems": info
|
"prefixItems": info
|
||||||
@ -157,27 +147,26 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
}),
|
}),
|
||||||
TypeInfo::List(info) => {
|
TypeInfo::List(info) => {
|
||||||
json!({
|
json!({
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"typeInfo": "List",
|
"typeInfo": "List",
|
||||||
"items": json!({"type": typ(info.item_type_path_table().path())}),
|
"items": json!({"type": typ(info.item_type_path_table().path())}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
TypeInfo::Array(info) => json!({
|
TypeInfo::Array(info) => json!({
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"typeInfo": "Array",
|
"typeInfo": "Array",
|
||||||
"items": json!({"type": typ(info.item_type_path_table().path())}),
|
"items": json!({"type": typ(info.item_type_path_table().path())}),
|
||||||
}),
|
}),
|
||||||
TypeInfo::Map(info) => json!({
|
TypeInfo::Map(info) => json!({
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"typeInfo": "Map",
|
"typeInfo": "Map",
|
||||||
"valueType": json!({"type": typ(info.value_type_path_table().path())}),
|
"additionalProperties": json!({"type": typ(info.value_type_path_table().path())}),
|
||||||
"keyType": json!({"type": typ(info.key_type_path_table().path())}),
|
|
||||||
}),
|
}),
|
||||||
TypeInfo::Tuple(info) => json!({
|
TypeInfo::Tuple(info) => json!({
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"typeInfo": "Tuple",
|
"typeInfo": "Tuple",
|
||||||
"prefixItems": info
|
"prefixItems": info
|
||||||
@ -188,7 +177,7 @@ pub fn export_type(reg: &TypeRegistration) -> (String, Value) {
|
|||||||
"items": false,
|
"items": false,
|
||||||
}),
|
}),
|
||||||
TypeInfo::Value(info) => json!({
|
TypeInfo::Value(info) => json!({
|
||||||
"long_name": t.type_path(),
|
"title": t.type_path(),
|
||||||
"type": map_json_type(info.type_path()),
|
"type": map_json_type(info.type_path()),
|
||||||
"typeInfo": "Value",
|
"typeInfo": "Value",
|
||||||
}),
|
}),
|
||||||
|
@ -16,9 +16,9 @@ use bevy::{
|
|||||||
pub struct ExportComponentsConfig {
|
pub struct ExportComponentsConfig {
|
||||||
pub(crate) save_path: PathBuf,
|
pub(crate) save_path: PathBuf,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) component_filter: SceneFilter,
|
pub(crate) component_filter: SceneFilter, // unused for now
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) resource_filter: SceneFilter,
|
pub(crate) resource_filter: SceneFilter, // unused for now
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExportRegistryPlugin {
|
pub struct ExportRegistryPlugin {
|
||||||
@ -30,8 +30,8 @@ pub struct ExportRegistryPlugin {
|
|||||||
impl Default for ExportRegistryPlugin {
|
impl Default for ExportRegistryPlugin {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
component_filter: SceneFilter::default(),
|
component_filter: SceneFilter::default(), // unused for now
|
||||||
resource_filter: SceneFilter::default(),
|
resource_filter: SceneFilter::default(), // unused for now
|
||||||
save_path: PathBuf::from("registry.json"), // relative to assets folder
|
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
|
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)
|
- [blenvy](https://github.com/kaosat-dev/Blenvy/tree/main/tools/blenvy)
|
||||||
- allows you to create a Json export of all your components/ registered types.
|
- 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).
|
(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/) .
|
- 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
|
* ability to specify **which resources** to save or to exclude
|
||||||
* small(er) save files (only a portion of the entities is saved)
|
* 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
|
## Usage
|
||||||
|
|
||||||
|
@ -354,12 +354,12 @@ pub(crate) fn blueprints_assets_loaded(
|
|||||||
// prepare data for animations
|
// prepare data for animations
|
||||||
let mut graph = AnimationGraph::new();
|
let mut graph = AnimationGraph::new();
|
||||||
let mut named_animations: HashMap<String, Handle<AnimationClip>> = HashMap::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() {
|
for (key, clip) in blueprint_gltf.named_animations.iter() {
|
||||||
named_animations.insert(key.to_string(), clip.clone());
|
named_animations.insert(key.to_string(), clip.clone());
|
||||||
let animation_index = graph.add_clip(clip.clone(), 1.0, graph.root);
|
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);
|
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
|
// 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
|
// these are animations specific to the blueprint
|
||||||
named_animations,
|
named_animations,
|
||||||
named_indices: animation_indices,
|
named_indices,
|
||||||
graph,
|
graph,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
Loading…
Reference in New Issue
Block a user