feat(Blenvy:Bevy): more work done on save & load (heavy wip)

* more coherent logic between save & load
 * added resources & boilerplate for loading side
 * experimenting with save & load logic, filtering of components etc
 * updated assets for more testing
 * added bevy-inspector-egui  to some examples for testing
This commit is contained in:
kaosat.dev 2024-08-07 01:36:06 +02:00
parent bd830e5ad4
commit e573251707
29 changed files with 1001 additions and 113 deletions

View File

@ -58,12 +58,12 @@ fn main() {
// add a system to trigger saving // add a system to trigger saving
pub fn request_save( pub fn request_save(
mut save_requests: EventWriter<SaveRequest>, mut save_requests: EventWriter<SavingRequest>,
keycode: Res<Input<KeyCode>>, keycode: Res<Input<KeyCode>>,
) )
{ {
if keycode.just_pressed(KeyCode::S) { if keycode.just_pressed(KeyCode::S) {
save_requests.send(SaveRequest { save_requests.send(SavingRequest {
path: "save.scn.ron".into(), path: "save.scn.ron".into(),
}) })
} }
@ -225,16 +225,16 @@ fn main() {
## Events ## Events
- to trigger **saving** use the ```SaveRequest``` event - to trigger **saving** use the ```SavingRequest``` event
```rust no_run ```rust no_run
// add a system to trigger saving // add a system to trigger saving
pub fn request_save( pub fn request_save(
mut save_requests: EventWriter<SaveRequest>, mut save_requests: EventWriter<SavingRequest>,
keycode: Res<Input<KeyCode>>, keycode: Res<Input<KeyCode>>,
) )
{ {
if keycode.just_pressed(KeyCode::S) { if keycode.just_pressed(KeyCode::S) {
save_requests.send(SaveRequest { save_requests.send(SavingRequest {
path: "save.scn.ron".into(), path: "save.scn.ron".into(),
}) })
} }

View File

@ -0,0 +1,45 @@
pub use bevy::prelude::*;
use crate::{BlueprintInfo, GameWorldTag, HideUntilReady, SpawnBlueprint};
use super::{BlueprintWorld, Dynamic};
pub(crate) fn spawn_from_blueprintworld(
added_blueprint_worlds: Query<(Entity, &BlueprintWorld), Added<BlueprintWorld> >,
mut commands: Commands,
){
for (entity, blueprint_world) in added_blueprint_worlds.iter(){
println!("added blueprintWorld {:?}", blueprint_world);
// here we spawn the static part our game world/level, which is also a blueprint !
let static_world = commands.spawn((
BlueprintInfo::from_path(blueprint_world.path.as_str()), // all we need is a Blueprint info...
SpawnBlueprint, // and spawnblueprint to tell blenvy to spawn the blueprint now
HideUntilReady, // only reveal the level once it is ready
GameWorldTag,
)).id();
// here we spawn the dynamic entities part of our game world/level, which is also a blueprint !
let dynamic_world = commands.spawn((
BlueprintInfo::from_path(blueprint_world.path.replace(".glb", "_dynamic.glb").replace(".gltf", "_dynamic.gltf").as_str()), // all we need is a Blueprint info...
SpawnBlueprint, // and spawnblueprint to tell blenvy to spawn the blueprint now
HideUntilReady, // only reveal the level once it is ready
GameWorldTag
)).id();
// commands.entity(entity).add_child(static_world);
// commands.entity(entity).add_child(dynamic_world);
}
}
pub(crate) fn inject_dynamic_into_children(
added_dynamic: Query<Entity, Added<Dynamic> >,
all_children: Query<&Children>,
mut commands: Commands,
) {
for entity in added_dynamic.iter() {
for child in all_children.iter_descendants(entity) {
commands.entity(child).insert(Dynamic);
}
}
}

View File

@ -0,0 +1,118 @@
use std::path::Path;
use bevy::prelude::*;
use crate::{BlenvyConfig, BlueprintInfo, DynamicEntitiesRoot, GameWorldTag, HideUntilReady, SpawnBlueprint};
#[derive(Event)]
pub struct LoadingRequest {
pub path: String,
}
#[derive(Event)]
pub struct LoadingFinished; // TODO: merge the two above
/// resource that keeps track of the current load request
#[derive(Resource, Default)]
pub struct LoadingRequested {
pub path: String,
}
/*
- Loading
- load request recieved
- pause things ?
- unload everything
- load static data using blueprintInfo
- load dynamic data from save file
General:
* wrap loading a bevy scene as a blueprint ?
* meh, has no assets & co, different logic ?
*/
pub fn process_load_requests(
mut load_requests: EventReader<LoadingRequest>,
mut commands: Commands
) {
let mut save_path: String = "".into();
for load_request in load_requests.read() {
if !load_request.path.is_empty() {
save_path.clone_from(&load_request.path);
}
}
if !save_path.is_empty() {
commands.insert_resource(LoadingRequested { path: save_path });
}
}
pub fn should_load(loading_requests: Option<Res<LoadingRequested>>) -> bool {
return resource_exists::<LoadingRequested>(loading_requests)
}
// TODO: replace with generic despawner ?
pub(crate) fn prepare_loading(
mut commands: Commands,
gameworlds: Query<Entity, With<GameWorldTag>>,
) {
for e in gameworlds.iter() {
info!("--loading: despawn old world/level");
commands.entity(e).despawn_recursive();
}
}
pub(crate) fn load_game(
mut commands: Commands,
asset_server: Res<AssetServer>,
load_request: Res<LoadingRequested>,
) {
info!("--loading: load dynamic data");
//let save_path = Path::new(load_request.path.clone().as_str());
info!("LOADING FROM {:?}", load_request.path.clone());
/*let world_root = commands
.spawn((
bevy::prelude::Name::from("world"),
GameWorldTag,
TransformBundle::default(),
InheritedVisibility::default(),
))
.id();*/
// and we fill it with dynamic data
// let input = std::fs::read(&path)?;
let dynamic_data = commands
.spawn((
DynamicSceneBundle {
scene: asset_server.load(load_request.path.clone()),
..default()
},
bevy::prelude::Name::from("World_dynamic"),
DynamicEntitiesRoot,
GameWorldTag
))
.id();
let static_data = commands.spawn((
BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info...
SpawnBlueprint,
HideUntilReady,
GameWorldTag,
)).id();
//commands.entity(world_root).add_child(static_data);
//commands.entity(world_root).add_child(dynamic_data);
// commands.insert_resource(LoadFirstStageDone);
info!("--loading: loaded dynamic data");
commands.remove_resource::<LoadingRequested>();
}

View File

@ -1,5 +1,15 @@
use std::path::Path;
use bevy::prelude::*; use bevy::prelude::*;
pub mod common;
pub use common::*;
pub mod saving;
pub use saving::*;
pub mod loading;
pub use loading::*;
#[derive(Component, Reflect, Debug, Default)] #[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)] #[reflect(Component)]
/// component used to mark any entity as Dynamic: aka add this to make sure your entity is going to be saved /// component used to mark any entity as Dynamic: aka add this to make sure your entity is going to be saved
@ -34,8 +44,22 @@ pub struct StaticEntitiesBlueprintInfo {
} }
pub mod saving;
pub use saving::*; #[derive(Component, Debug)]
pub struct BlueprintWorld{
pub path: String,
}
impl BlueprintWorld {
pub fn from_path(path: &str) -> BlueprintWorld {
let p = Path::new(&path);
return BlueprintWorld {
// name: p.file_stem().unwrap().to_os_string().into_string().unwrap(), // seriously ? , also unwraps !!
path: path.into(),
};
}
}
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
/// Plugin for saving & loading /// Plugin for saving & loading
@ -46,13 +70,33 @@ impl Plugin for SaveLoadPlugin {
app.register_type::<Dynamic>() app.register_type::<Dynamic>()
.register_type::<StaticEntitiesRoot>() .register_type::<StaticEntitiesRoot>()
.add_event::<SaveRequest>() .add_event::<SavingRequest>()
.add_event::<SaveFinished>() .add_event::<SaveFinished>()
// common
.add_systems(Update, (spawn_from_blueprintworld, )) // inject_dynamic_into_children
// saving
.add_systems(Update, process_save_requests)
.add_systems( .add_systems(
Update, Update,
(prepare_save_game, apply_deferred, save_game, cleanup_save) (prepare_save_game, apply_deferred, save_game, cleanup_save)
.chain() .chain()
.run_if(should_save), .run_if(should_save),
)
.add_event::<LoadingRequest>()
.add_event::<LoadingFinished>()
//loading
.add_systems(Update, process_load_requests)
.add_systems(
Update,
(prepare_loading, apply_deferred, load_game)
.chain()
.run_if(should_load),
//.run_if(not(resource_exists::<LoadFirstStageDone>))
// .in_set(LoadingSet::Load),
) )
; ;
} }

View File

@ -5,7 +5,7 @@ use std::path::Path;
use crate::{DynamicEntitiesRoot, SaveLoadConfig, StaticEntitiesRoot, StaticEntitiesStorage}; use crate::{DynamicEntitiesRoot, SaveLoadConfig, StaticEntitiesRoot, StaticEntitiesStorage};
#[derive(Event)] #[derive(Event)]
pub struct LoadRequest { pub struct LoadingRequest {
pub path: String, pub path: String,
} }
@ -26,7 +26,7 @@ pub(crate) struct CleanupScene;
/// helper system that "converts" loadRequest events to `LoadRequested` resources /// helper system that "converts" loadRequest events to `LoadRequested` resources
pub(crate) fn mark_load_requested( pub(crate) fn mark_load_requested(
mut load_requests: EventReader<LoadRequest>, mut load_requests: EventReader<LoadingRequest>,
mut commands: Commands, mut commands: Commands,
) { ) {
let mut save_path: String = "".into(); let mut save_path: String = "".into();

View File

@ -41,8 +41,8 @@ impl Plugin for SaveLoadPlugin {
.register_type::<Camera3dDepthTextureUsage>() .register_type::<Camera3dDepthTextureUsage>()
.register_type::<ScreenSpaceTransmissionQuality>() .register_type::<ScreenSpaceTransmissionQuality>()
.register_type::<StaticEntitiesStorage>() .register_type::<StaticEntitiesStorage>()
.add_event::<SaveRequest>() .add_event::<SavingRequest>()
.add_event::<LoadRequest>() .add_event::<LoadingRequest>()
.add_event::<LoadingFinished>() .add_event::<LoadingFinished>()
.add_event::<SavingFinished>() .add_event::<SavingFinished>()
.configure_sets( .configure_sets(

View File

@ -9,14 +9,14 @@ use std::path::Path;
use crate::{DynamicEntitiesRoot, SaveLoadConfig, StaticEntitiesRoot}; use crate::{DynamicEntitiesRoot, SaveLoadConfig, StaticEntitiesRoot};
#[derive(Event, Debug)] #[derive(Event, Debug)]
pub struct SaveRequest { pub struct SavingRequest {
pub path: String, pub path: String,
} }
#[derive(Event)] #[derive(Event)]
pub struct SavingFinished; pub struct SavingFinished;
pub fn should_save(save_requests: EventReader<SaveRequest>) -> bool { pub fn should_save(save_requests: EventReader<SavingRequest>) -> bool {
!save_requests.is_empty() !save_requests.is_empty()
} }
@ -77,7 +77,7 @@ pub(crate) fn save_game(world: &mut World) {
info!("saving"); info!("saving");
let mut save_path: String = "".into(); let mut save_path: String = "".into();
let mut events = world.resource_mut::<Events<SaveRequest>>(); let mut events = world.resource_mut::<Events<SavingRequest>>();
for event in events.get_reader().read(&events) { for event in events.get_reader().read(&events) {
info!("SAVE EVENT !! {:?}", event); info!("SAVE EVENT !! {:?}", event);

View File

@ -11,14 +11,38 @@ use crate::{BlenvyConfig, BlueprintInfo, Dynamic, FromBlueprint, RootEntity, Spa
use super::{DynamicEntitiesRoot, OriginalParent, StaticEntitiesRoot}; use super::{DynamicEntitiesRoot, OriginalParent, StaticEntitiesRoot};
#[derive(Event, Debug)] #[derive(Event, Debug)]
pub struct SaveRequest { pub struct SavingRequest {
pub path: String, pub path: String,
} }
#[derive(Event)] #[derive(Event)]
pub struct SaveFinished; // TODO: merge the the events above pub struct SaveFinished; // TODO: merge the the events above
pub fn should_save(save_requests: EventReader<SaveRequest>) -> bool {
!save_requests.is_empty() /// resource that keeps track of the current save request
#[derive(Resource, Default)]
pub struct SavingRequested {
pub path: String,
}
pub fn process_save_requests(
mut saving_requests: EventReader<SavingRequest>,
mut commands: Commands
) {
let mut save_path: String = "".into();
for saving_request in saving_requests.read() {
if !saving_request.path.is_empty() {
save_path.clone_from(&saving_request.path);
}
}
if !save_path.is_empty() {
commands.insert_resource(SavingRequested { path: save_path });
}
}
pub fn should_save(saving_requests: Option<Res<SavingRequested>>) -> bool {
return resource_exists::<SavingRequested>(saving_requests)
} }
@ -31,12 +55,12 @@ pub(crate) fn prepare_save_game(
mut commands: Commands, mut commands: Commands,
) { ) {
for entity in saveables.iter() { for entity in saveables.iter() { // FIXME : not sure about this one
commands.entity(entity).insert(SpawnBlueprint); commands.entity(entity).insert(SpawnBlueprint);
} }
for (entity, parent, children) in dynamic_entities.iter() { for (entity, parent, children) in dynamic_entities.iter() {
println!("prepare save game"); println!("prepare save game for entity");
let parent = parent.get(); let parent = parent.get();
if root_entities.contains(parent) { if root_entities.contains(parent) {
commands.entity(entity).insert(RootEntity); commands.entity(entity).insert(RootEntity);
@ -66,7 +90,7 @@ pub(crate) fn save_game(world: &mut World) {
info!("saving"); info!("saving");
let mut save_path: String = "".into(); let mut save_path: String = "".into();
let mut events = world.resource_mut::<Events<SaveRequest>>(); let mut events = world.resource_mut::<Events<SavingRequest>>();
for event in events.get_reader().read(&events) { for event in events.get_reader().read(&events) {
info!("SAVE EVENT !! {:?}", event); info!("SAVE EVENT !! {:?}", event);
@ -75,14 +99,14 @@ pub(crate) fn save_game(world: &mut World) {
events.clear(); events.clear();
let saveable_entities: Vec<Entity> = world let saveable_entities: Vec<Entity> = world
// .query_filtered::<Entity, (With<Dynamic>, Without<FromBlueprint>, Without<RootEntity>)>()
.query_filtered::<Entity, (With<Dynamic>, Without<RootEntity>)>() .query_filtered::<Entity, (With<Dynamic>, Without<RootEntity>)>()
// .query_filtered::<Entity, (With<Dynamic>, Without<FromBlueprint>, Without<RootEntity>)>()
.iter(world) .iter(world)
.collect(); .collect();
let saveable_root_entities: Vec<Entity> = world let saveable_root_entities: Vec<Entity> = world
.query_filtered::<Entity, (With<Dynamic>, With<RootEntity>)>() // .query_filtered::<Entity, (With<Dynamic>, With<RootEntity>)>()
//.query_filtered::<Entity, (With<Dynamic>, Without<FromBlueprint>, With<RootEntity>)>() .query_filtered::<Entity, (With<Dynamic>, Without<FromBlueprint>, With<RootEntity>)>()
.iter(world) .iter(world)
.collect(); .collect();
@ -97,7 +121,7 @@ pub(crate) fn save_game(world: &mut World) {
let filter = config let filter = config
.save_component_filter .save_component_filter
.clone() .clone()
.allow::<Parent>() //.allow::<Parent>() // TODO: add back
.allow::<Children>() .allow::<Children>()
.allow::<BlueprintInfo>() .allow::<BlueprintInfo>()
.allow::<SpawnBlueprint>() .allow::<SpawnBlueprint>()
@ -115,7 +139,6 @@ pub(crate) fn save_game(world: &mut World) {
let filter_resources = config.clone() let filter_resources = config.clone()
.save_resource_filter .save_resource_filter
.deny::<Time<Real>>() .deny::<Time<Real>>()
.clone(); .clone();
//.allow::<StaticEntitiesStorage>(); //.allow::<StaticEntitiesStorage>();
@ -150,22 +173,37 @@ pub(crate) fn save_game(world: &mut World) {
.serialize(&world.resource::<AppTypeRegistry>().read()) .serialize(&world.resource::<AppTypeRegistry>().read())
.expect("filtered scene should serialize correctly"); .expect("filtered scene should serialize correctly");
let save_path = Path::new("assets") let save_path_assets = Path::new("assets")
//.join(&config.save_path) //.join(&config.save_path)
.join(Path::new(save_path.as_str())); // Path::new(&save_load_config.save_path).join(Path::new(save_path.as_str())); .join(Path::new(save_path.as_str())); // Path::new(&save_load_config.save_path).join(Path::new(save_path.as_str()));
info!("saving game to {:?}", save_path); info!("saving game to {:?}", save_path_assets);
// world.send_event(SavingFinished); // world.send_event(SavingFinished);
let bla = save_path_assets.clone().to_string_lossy().into_owned();
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
IoTaskPool::get() IoTaskPool::get()
.spawn(async move { .spawn(async move {
// Write the scene RON data to file // Write the scene RON data to file
File::create(save_path) File::create(save_path_assets)
.and_then(|mut file| file.write(serialized_scene.as_bytes())) .and_then(|mut file| file.write(serialized_scene.as_bytes()))
.expect("Error while writing save to file"); .expect("Error while writing save to file");
}) })
.detach(); .detach();
let static_world_path = "levels/world.glb";
let fake_foo = format!("(dynamic: {bla}, static: {static_world_path})");
let real_save_path = format!("{bla}.save.ron");
#[cfg(not(target_arch = "wasm32"))]
IoTaskPool::get()
.spawn(async move {
// Write the scene RON data to file
File::create(real_save_path)
.and_then(|mut file| file.write(fake_foo.as_bytes()))
.expect("Error while writing scene to file");
})
.detach();
} }
pub(crate) fn cleanup_save( pub(crate) fn cleanup_save(
@ -178,4 +216,7 @@ pub(crate) fn cleanup_save(
} }
// commands.remove_resource::<StaticEntitiesStorage>(); // commands.remove_resource::<StaticEntitiesStorage>();
saving_finished.send(SaveFinished); saving_finished.send(SaveFinished);
commands.remove_resource::<SavingRequested>();
} }

View File

@ -10,4 +10,9 @@ blenvy = { path = "../../crates/blenvy" }
serde_json = "1.0.108" serde_json = "1.0.108"
serde = "1.0.193" serde = "1.0.193"
rand = "0.8.5" rand = "0.8.5"
bevy-inspector-egui = { version = "0.25.1"}
[dev-dependencies]
bevy-inspector-egui = { version = "0.25.1"}

View File

@ -0,0 +1 @@
(dynamic: assets/, static: levels/world.glb)

View File

@ -0,0 +1,5 @@
(
assets:
[
]
)

View File

@ -0,0 +1,7 @@
(
assets:
[
("Mover", File ( path: "blueprints/Mover.glb" )),
("Material.001", File ( path: "materials/Material.001.glb" )),
]
)

View File

@ -5,5 +5,9 @@
("Stone", File ( path: "materials/Stone.glb" )), ("Stone", File ( path: "materials/Stone.glb" )),
("Mover", File ( path: "blueprints/Mover.glb" )), ("Mover", File ( path: "blueprints/Mover.glb" )),
("Material.001", File ( path: "materials/Material.001.glb" )), ("Material.001", File ( path: "materials/Material.001.glb" )),
("Dynamic_hierarchy", File ( path: "blueprints/Dynamic_hierarchy.glb" )),
("Dynamic_inside_static", File ( path: "blueprints/Dynamic_inside_static.glb" )),
("Mover", File ( path: "blueprints/Mover.glb" )),
("Material.001", File ( path: "materials/Material.001.glb" )),
] ]
) )

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3609,6 +3609,30 @@
"type": "object", "type": "object",
"typeInfo": "Value" "typeInfo": "Value"
}, },
"bevy_egui::EguiSettings": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "bevy_egui::EguiSettings",
"properties": {
"default_open_url_target": {
"type": {
"$ref": "#/$defs/core::option::Option<alloc::string::String>"
}
},
"scale_factor": {
"type": {
"$ref": "#/$defs/f32"
}
}
},
"required": [
"scale_factor"
],
"short_name": "EguiSettings",
"type": "object",
"typeInfo": "Struct"
},
"bevy_gizmos::aabb::AabbGizmoConfigGroup": { "bevy_gizmos::aabb::AabbGizmoConfigGroup": {
"additionalProperties": false, "additionalProperties": false,
"isComponent": false, "isComponent": false,
@ -12947,6 +12971,14 @@
"type": "object", "type": "object",
"typeInfo": "Value" "typeInfo": "Value"
}, },
"core::ops::Range<f64>": {
"isComponent": false,
"isResource": false,
"long_name": "core::ops::Range<f64>",
"short_name": "Range<f64>",
"type": "object",
"typeInfo": "Value"
},
"core::option::Option<(u8, u8)>": { "core::option::Option<(u8, u8)>": {
"isComponent": false, "isComponent": false,
"isResource": false, "isResource": false,
@ -13661,6 +13693,295 @@
"type": "object", "type": "object",
"typeInfo": "Struct" "typeInfo": "Struct"
}, },
"glam::BVec2": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::BVec2",
"properties": {
"x": {
"type": {
"$ref": "#/$defs/bool"
}
},
"y": {
"type": {
"$ref": "#/$defs/bool"
}
}
},
"required": [
"x",
"y"
],
"short_name": "BVec2",
"type": "object",
"typeInfo": "Struct"
},
"glam::BVec3": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::BVec3",
"properties": {
"x": {
"type": {
"$ref": "#/$defs/bool"
}
},
"y": {
"type": {
"$ref": "#/$defs/bool"
}
},
"z": {
"type": {
"$ref": "#/$defs/bool"
}
}
},
"required": [
"x",
"y",
"z"
],
"short_name": "BVec3",
"type": "object",
"typeInfo": "Struct"
},
"glam::BVec3A": {
"isComponent": false,
"isResource": false,
"long_name": "glam::BVec3A",
"short_name": "BVec3A",
"type": "object",
"typeInfo": "Value"
},
"glam::BVec4": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::BVec4",
"properties": {
"w": {
"type": {
"$ref": "#/$defs/bool"
}
},
"x": {
"type": {
"$ref": "#/$defs/bool"
}
},
"y": {
"type": {
"$ref": "#/$defs/bool"
}
},
"z": {
"type": {
"$ref": "#/$defs/bool"
}
}
},
"required": [
"x",
"y",
"z",
"w"
],
"short_name": "BVec4",
"type": "object",
"typeInfo": "Struct"
},
"glam::BVec4A": {
"isComponent": false,
"isResource": false,
"long_name": "glam::BVec4A",
"short_name": "BVec4A",
"type": "object",
"typeInfo": "Value"
},
"glam::DAffine2": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DAffine2",
"properties": {
"matrix2": {
"type": {
"$ref": "#/$defs/glam::DMat2"
}
},
"translation": {
"type": {
"$ref": "#/$defs/glam::DVec2"
}
}
},
"required": [
"matrix2",
"translation"
],
"short_name": "DAffine2",
"type": "object",
"typeInfo": "Struct"
},
"glam::DAffine3": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DAffine3",
"properties": {
"matrix3": {
"type": {
"$ref": "#/$defs/glam::DMat3"
}
},
"translation": {
"type": {
"$ref": "#/$defs/glam::DVec3"
}
}
},
"required": [
"matrix3",
"translation"
],
"short_name": "DAffine3",
"type": "object",
"typeInfo": "Struct"
},
"glam::DMat2": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DMat2",
"properties": {
"x_axis": {
"type": {
"$ref": "#/$defs/glam::DVec2"
}
},
"y_axis": {
"type": {
"$ref": "#/$defs/glam::DVec2"
}
}
},
"required": [
"x_axis",
"y_axis"
],
"short_name": "DMat2",
"type": "object",
"typeInfo": "Struct"
},
"glam::DMat3": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DMat3",
"properties": {
"x_axis": {
"type": {
"$ref": "#/$defs/glam::DVec3"
}
},
"y_axis": {
"type": {
"$ref": "#/$defs/glam::DVec3"
}
},
"z_axis": {
"type": {
"$ref": "#/$defs/glam::DVec3"
}
}
},
"required": [
"x_axis",
"y_axis",
"z_axis"
],
"short_name": "DMat3",
"type": "object",
"typeInfo": "Struct"
},
"glam::DMat4": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DMat4",
"properties": {
"w_axis": {
"type": {
"$ref": "#/$defs/glam::DVec4"
}
},
"x_axis": {
"type": {
"$ref": "#/$defs/glam::DVec4"
}
},
"y_axis": {
"type": {
"$ref": "#/$defs/glam::DVec4"
}
},
"z_axis": {
"type": {
"$ref": "#/$defs/glam::DVec4"
}
}
},
"required": [
"x_axis",
"y_axis",
"z_axis",
"w_axis"
],
"short_name": "DMat4",
"type": "object",
"typeInfo": "Struct"
},
"glam::DQuat": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DQuat",
"properties": {
"w": {
"type": {
"$ref": "#/$defs/f64"
}
},
"x": {
"type": {
"$ref": "#/$defs/f64"
}
},
"y": {
"type": {
"$ref": "#/$defs/f64"
}
},
"z": {
"type": {
"$ref": "#/$defs/f64"
}
}
},
"required": [
"x",
"y",
"z",
"w"
],
"short_name": "DQuat",
"type": "object",
"typeInfo": "Struct"
},
"glam::DVec2": { "glam::DVec2": {
"additionalProperties": false, "additionalProperties": false,
"isComponent": false, "isComponent": false,
@ -13686,6 +14007,74 @@
"type": "object", "type": "object",
"typeInfo": "Struct" "typeInfo": "Struct"
}, },
"glam::DVec3": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DVec3",
"properties": {
"x": {
"type": {
"$ref": "#/$defs/f64"
}
},
"y": {
"type": {
"$ref": "#/$defs/f64"
}
},
"z": {
"type": {
"$ref": "#/$defs/f64"
}
}
},
"required": [
"x",
"y",
"z"
],
"short_name": "DVec3",
"type": "object",
"typeInfo": "Struct"
},
"glam::DVec4": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::DVec4",
"properties": {
"w": {
"type": {
"$ref": "#/$defs/f64"
}
},
"x": {
"type": {
"$ref": "#/$defs/f64"
}
},
"y": {
"type": {
"$ref": "#/$defs/f64"
}
},
"z": {
"type": {
"$ref": "#/$defs/f64"
}
}
},
"required": [
"x",
"y",
"z",
"w"
],
"short_name": "DVec4",
"type": "object",
"typeInfo": "Struct"
},
"glam::IVec2": { "glam::IVec2": {
"additionalProperties": false, "additionalProperties": false,
"isComponent": false, "isComponent": false,
@ -13711,6 +14100,74 @@
"type": "object", "type": "object",
"typeInfo": "Struct" "typeInfo": "Struct"
}, },
"glam::IVec3": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::IVec3",
"properties": {
"x": {
"type": {
"$ref": "#/$defs/i32"
}
},
"y": {
"type": {
"$ref": "#/$defs/i32"
}
},
"z": {
"type": {
"$ref": "#/$defs/i32"
}
}
},
"required": [
"x",
"y",
"z"
],
"short_name": "IVec3",
"type": "object",
"typeInfo": "Struct"
},
"glam::IVec4": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::IVec4",
"properties": {
"w": {
"type": {
"$ref": "#/$defs/i32"
}
},
"x": {
"type": {
"$ref": "#/$defs/i32"
}
},
"y": {
"type": {
"$ref": "#/$defs/i32"
}
},
"z": {
"type": {
"$ref": "#/$defs/i32"
}
}
},
"required": [
"x",
"y",
"z",
"w"
],
"short_name": "IVec4",
"type": "object",
"typeInfo": "Struct"
},
"glam::Mat2": { "glam::Mat2": {
"additionalProperties": false, "additionalProperties": false,
"isComponent": false, "isComponent": false,
@ -13736,6 +14193,37 @@
"type": "object", "type": "object",
"typeInfo": "Struct" "typeInfo": "Struct"
}, },
"glam::Mat3": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::Mat3",
"properties": {
"x_axis": {
"type": {
"$ref": "#/$defs/glam::Vec3"
}
},
"y_axis": {
"type": {
"$ref": "#/$defs/glam::Vec3"
}
},
"z_axis": {
"type": {
"$ref": "#/$defs/glam::Vec3"
}
}
},
"required": [
"x_axis",
"y_axis",
"z_axis"
],
"short_name": "Mat3",
"type": "object",
"typeInfo": "Struct"
},
"glam::Mat3A": { "glam::Mat3A": {
"additionalProperties": false, "additionalProperties": false,
"isComponent": false, "isComponent": false,
@ -13897,6 +14385,43 @@
"type": "object", "type": "object",
"typeInfo": "Struct" "typeInfo": "Struct"
}, },
"glam::UVec4": {
"additionalProperties": false,
"isComponent": false,
"isResource": false,
"long_name": "glam::UVec4",
"properties": {
"w": {
"type": {
"$ref": "#/$defs/u32"
}
},
"x": {
"type": {
"$ref": "#/$defs/u32"
}
},
"y": {
"type": {
"$ref": "#/$defs/u32"
}
},
"z": {
"type": {
"$ref": "#/$defs/u32"
}
}
},
"required": [
"x",
"y",
"z",
"w"
],
"short_name": "UVec4",
"type": "object",
"typeInfo": "Struct"
},
"glam::Vec2": { "glam::Vec2": {
"additionalProperties": false, "additionalProperties": false,
"isComponent": false, "isComponent": false,

View File

@ -8,22 +8,22 @@
), ),
delta: ( delta: (
secs: 0, secs: 0,
nanos: 19854342, nanos: 20094396,
), ),
delta_seconds: 0.019854343, delta_seconds: 0.020094397,
delta_seconds_f64: 0.019854342, delta_seconds_f64: 0.020094396,
elapsed: ( elapsed: (
secs: 0, secs: 1,
nanos: 579651002, nanos: 493224348,
), ),
elapsed_seconds: 0.579651, elapsed_seconds: 1.4932244,
elapsed_seconds_f64: 0.579651002, elapsed_seconds_f64: 1.493224348,
elapsed_wrapped: ( elapsed_wrapped: (
secs: 0, secs: 1,
nanos: 579651002, nanos: 493224348,
), ),
elapsed_seconds_wrapped: 0.579651, elapsed_seconds_wrapped: 1.4932244,
elapsed_seconds_wrapped_f64: 0.579651002, elapsed_seconds_wrapped_f64: 1.493224348,
), ),
"bevy_time::time::Time<bevy_time::virt::Virtual>": ( "bevy_time::time::Time<bevy_time::virt::Virtual>": (
context: ( context: (
@ -41,22 +41,22 @@
), ),
delta: ( delta: (
secs: 0, secs: 0,
nanos: 19854342, nanos: 20094396,
), ),
delta_seconds: 0.019854343, delta_seconds: 0.020094397,
delta_seconds_f64: 0.019854342, delta_seconds_f64: 0.020094396,
elapsed: ( elapsed: (
secs: 0, secs: 1,
nanos: 579651002, nanos: 493224348,
), ),
elapsed_seconds: 0.579651, elapsed_seconds: 1.4932244,
elapsed_seconds_f64: 0.579651002, elapsed_seconds_f64: 1.493224348,
elapsed_wrapped: ( elapsed_wrapped: (
secs: 0, secs: 1,
nanos: 579651002, nanos: 493224348,
), ),
elapsed_seconds_wrapped: 0.579651, elapsed_seconds_wrapped: 1.4932244,
elapsed_seconds_wrapped_f64: 0.579651002, elapsed_seconds_wrapped_f64: 1.493224348,
), ),
"bevy_time::time::Time<bevy_time::fixed::Fixed>": ( "bevy_time::time::Time<bevy_time::fixed::Fixed>": (
context: ( context: (
@ -66,7 +66,7 @@
), ),
overstep: ( overstep: (
secs: 0, secs: 0,
nanos: 1526002, nanos: 8849348,
), ),
), ),
wrap_period: ( wrap_period: (
@ -80,17 +80,17 @@
delta_seconds: 0.015625, delta_seconds: 0.015625,
delta_seconds_f64: 0.015625, delta_seconds_f64: 0.015625,
elapsed: ( elapsed: (
secs: 0, secs: 1,
nanos: 578125000, nanos: 484375000,
), ),
elapsed_seconds: 0.578125, elapsed_seconds: 1.484375,
elapsed_seconds_f64: 0.578125, elapsed_seconds_f64: 1.484375,
elapsed_wrapped: ( elapsed_wrapped: (
secs: 0, secs: 1,
nanos: 578125000, nanos: 484375000,
), ),
elapsed_seconds_wrapped: 0.578125, elapsed_seconds_wrapped: 1.484375,
elapsed_seconds_wrapped_f64: 0.578125, elapsed_seconds_wrapped_f64: 1.484375,
), ),
"bevy_render::camera::clear_color::ClearColor": (Srgba(( "bevy_render::camera::clear_color::ClearColor": (Srgba((
red: 0.16862746, red: 0.16862746,
@ -125,16 +125,68 @@
"bevy_gizmos::config::GizmoConfigStore": (), "bevy_gizmos::config::GizmoConfigStore": (),
}, },
entities: { entities: {
4294967309: ( 4294967311: (
components: { components: {
"blenvy::blueprints::spawn_from_blueprints::BlueprintInfo": (
name: "Mover",
path: "blueprints/Mover.glb",
),
"blenvy::blueprints::spawn_from_blueprints::SpawnBlueprint": (),
"bevy_transform::components::transform::Transform": ( "bevy_transform::components::transform::Transform": (
translation: ( translation: (
x: 0.19871584, x: -2.217765,
y: 1.2997229,
z: 2.3971958,
),
rotation: (
x: 0.10570976,
y: 0.038342018,
z: 0.09289465,
w: 0.9893058,
),
scale: (
x: 0.53947395,
y: 0.53947395,
z: 0.5394739,
),
),
"bevy_transform::components::global_transform::GlobalTransform": ((
matrix3: (
x_axis: (
x: 0.5285771,
y: 0.10352973,
z: -0.030331498,
),
y_axis: (
x: -0.094783515,
y: 0.5181065,
z: 0.11667855,
),
z_axis: (
x: 0.051521756,
y: -0.10899262,
z: 0.5258309,
),
),
translation: (
x: -2.2227652,
y: 1.2997229,
z: 2.3971958,
),
)),
"blenvy::blueprints::spawn_from_blueprints::BlueprintInfo": (
name: "Dynamic_hierarchy",
path: "blueprints/Dynamic_hierarchy.glb",
),
"bevy_core::name::Name": (
hash: 1803003925387469959,
name: "Dynamic_hierarchy",
),
"blenvy::save_load::Dynamic": (),
"blenvy::blueprints::spawn_from_blueprints::SpawnBlueprint": (),
"bevy_render::view::visibility::InheritedVisibility": (true),
},
),
4294967312: (
components: {
"bevy_transform::components::transform::Transform": (
translation: (
x: 0.2887157,
y: 1.19514, y: 1.19514,
z: -0.7909124, z: -0.7909124,
), ),
@ -169,17 +221,78 @@
), ),
), ),
translation: ( translation: (
x: 0.18871583, x: 0.2837157,
y: 1.19514, y: 1.19514,
z: -0.7909124, z: -0.7909124,
), ),
)), )),
"bevy_hierarchy::components::parent::Parent": (21474836492), "blenvy::blueprints::spawn_from_blueprints::BlueprintInfo": (
name: "Mover",
path: "blueprints/Mover.glb",
),
"bevy_core::name::Name": ( "bevy_core::name::Name": (
hash: 10742641839607126956, hash: 3988719516189002069,
name: "Mover", name: "Mover",
), ),
"blenvy::save_load::Dynamic": (), "blenvy::save_load::Dynamic": (),
"blenvy::blueprints::spawn_from_blueprints::SpawnBlueprint": (),
"bevy_render::view::visibility::InheritedVisibility": (true),
},
),
21474836498: (
components: {
"bevy_transform::components::transform::Transform": (
translation: (
x: 1.6942285,
y: 0.50783855,
z: -2.0131574,
),
rotation: (
x: 0.0,
y: 0.0,
z: 0.0,
w: 1.0,
),
scale: (
x: 1.0,
y: 1.0,
z: 1.0,
),
),
"bevy_transform::components::global_transform::GlobalTransform": ((
matrix3: (
x_axis: (
x: 0.6095814,
y: 0.1066819,
z: -0.10043551,
),
y_axis: (
x: -0.08811652,
y: 0.6102711,
z: 0.113412924,
),
z_axis: (
x: 0.11706323,
y: -0.096156046,
z: 0.60836506,
),
),
translation: (
x: -1.6649909,
y: 1.184185,
z: 2.0619445,
),
)),
"blenvy::blueprints::spawn_from_blueprints::BlueprintInfo": (
name: "Mover",
path: "blueprints/Mover.glb",
),
"bevy_core::name::Name": (
hash: 14976337147749212273,
name: "Mover.001",
),
"blenvy::save_load::Dynamic": (),
"blenvy::blueprints::spawn_from_blueprints::SpawnBlueprint": (),
"bevy_render::view::visibility::InheritedVisibility": (true), "bevy_render::view::visibility::InheritedVisibility": (true),
}, },
), ),

View File

@ -0,0 +1 @@
(dynamic: assets/scenes/save.scn.ron, static: levels/world.glb)

View File

@ -12,10 +12,10 @@ pub mod in_game_saving;
pub use in_game_saving::*; pub use in_game_saving::*;
use bevy::prelude::*; use bevy::prelude::*;
use blenvy::{LoadRequest, LoadingFinished, SaveRequest, SavingFinished}; use blenvy::{LoadRequest, LoadingFinished, SavingRequest, SavingFinished};
pub fn request_save( pub fn request_save(
mut save_requests: EventWriter<SaveRequest>, mut save_requests: EventWriter<SavingRequest>,
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
current_state: Res<State<GameState>>, current_state: Res<State<GameState>>,
@ -26,7 +26,7 @@ pub fn request_save(
&& (current_state.get() != &GameState::InSaving) && (current_state.get() != &GameState::InSaving)
{ {
next_game_state.set(GameState::InSaving); next_game_state.set(GameState::InSaving);
save_requests.send(SaveRequest { save_requests.send(SavingRequest {
path: "save.scn.ron".into(), path: "save.scn.ron".into(),
}); });
} }

View File

@ -1,7 +1,7 @@
use std::any::TypeId; use std::any::TypeId;
use bevy::{prelude::*, utils::hashbrown::HashSet}; use bevy::{prelude::*, utils::hashbrown::HashSet};
use blenvy::{AddToGameWorld, BlenvyPlugin, BluePrintBundle, BlueprintInfo, Dynamic, DynamicBlueprintInstance, GameWorldTag, HideUntilReady, SaveRequest, SpawnBlueprint}; use blenvy::{AddToGameWorld, BlenvyPlugin, BlueprintInfo, BlueprintWorld, Dynamic, DynamicBlueprintInstance, GameWorldTag, HideUntilReady, LoadingRequest, SavingRequest, SpawnBlueprint};
use rand::Rng; use rand::Rng;
// mod game; // mod game;
@ -9,11 +9,13 @@ use rand::Rng;
mod component_examples; mod component_examples;
use component_examples::*; use component_examples::*;
use bevy_inspector_egui::quick::WorldInspectorPlugin;
fn main() { fn main() {
App::new() App::new()
.add_plugins(( .add_plugins((
DefaultPlugins.set(AssetPlugin::default()), DefaultPlugins.set(AssetPlugin::default()),
WorldInspectorPlugin::new(),
BlenvyPlugin { BlenvyPlugin {
save_component_filter: SceneFilter::Allowlist(HashSet::from([ save_component_filter: SceneFilter::Allowlist(HashSet::from([
TypeId::of::<Name>(), TypeId::of::<Name>(),
@ -49,19 +51,10 @@ fn setup_game(
mut commands: Commands, mut commands: Commands,
) { ) {
// here we spawn our game world/level, which is also a blueprint !
// would be nice: contains both static & dynamic stuff
commands.spawn(( commands.spawn((
BlueprintInfo::from_path("levels/World.glb"), // all we need is a Blueprint info... BlueprintWorld::from_path("levels/World.glb"), // will take care of loading both static & dynamic data
SpawnBlueprint, // and spawnblueprint to tell blenvy to spawn the blueprint now
HideUntilReady, // only reveal the level once it is ready
GameWorldTag,
));
// here we spawn our game world/level, which is also a blueprint !
commands.spawn((
BlueprintInfo::from_path("levels/World_dynamic.glb"), // all we need is a Blueprint info...
SpawnBlueprint, // and spawnblueprint to tell blenvy to spawn the blueprint now
HideUntilReady, // only reveal the level once it is ready
)); ));
} }
@ -97,47 +90,30 @@ fn move_movers(
mut movers: Query<(&mut Transform), With<Dynamic>> mut movers: Query<(&mut Transform), With<Dynamic>>
) { ) {
for mut transform in movers.iter_mut(){ for mut transform in movers.iter_mut(){
println!("moving dynamic entity"); // println!("moving dynamic entity");
transform.translation.x += 0.01; transform.translation.x += 0.005;
} }
} }
fn save_game( fn save_game(
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
mut save_requests: EventWriter<SaveRequest>, mut save_requests: EventWriter<SavingRequest>,
) { ) {
if keycode.just_pressed(KeyCode::KeyS) { if keycode.just_pressed(KeyCode::KeyS) {
save_requests.send(SaveRequest { save_requests.send(SavingRequest {
path: "scenes/save.scn.ron".into(), path: "scenes/save.scn.ron".into(),
}); });
} }
} }
/*
pub fn request_save(
mut save_requests: EventWriter<SaveRequest>,
keycode: Res<ButtonInput<KeyCode>>,
current_state: Res<State<GameState>>,
mut next_game_state: ResMut<NextState<GameState>>,
) {
if keycode.just_pressed(KeyCode::KeyS)
&& (current_state.get() != &GameState::InLoading)
&& (current_state.get() != &GameState::InSaving)
{
next_game_state.set(GameState::InSaving);
save_requests.send(SaveRequest {
path: "save.scn.ron".into(),
});
}
}*/
fn load_game( fn load_game(
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
mut load_requests: EventWriter<LoadingRequest>,
) { ) {
if keycode.just_pressed(KeyCode::KeyL) { if keycode.just_pressed(KeyCode::KeyL) {
load_requests.send(LoadingRequest {
path: "scenes/save.scn.ron".into(),
});
} }
} }

View File

@ -9,4 +9,7 @@ bevy = { version = "0.14", features = ["dynamic_linking"] }
blenvy = { path = "../../crates/blenvy" } blenvy = { path = "../../crates/blenvy" }
#bevy_editor_pls = { version = "0.8" } #bevy_editor_pls = { version = "0.8" }
rand = "0.8.5" rand = "0.8.5"
json-writer ="0.3" json-writer ="0.3"
[dev-dependencies]
bevy-inspector-egui = { version = "0.25.1"}