Compare commits

..

No commits in common. "d08c235122e3360e691fcb0f6cbb4f9de65e65b9" and "3a528e447ab34a5bcd44768d12af8e5b23617cfd" have entirely different histories.

33 changed files with 1273 additions and 14807 deletions

View File

@ -10,9 +10,6 @@ pub use registry::*;
pub mod blueprints; pub mod blueprints;
pub use blueprints::*; pub use blueprints::*;
pub mod save_load;
pub use save_load::*;
#[derive(Clone, Resource)] #[derive(Clone, Resource)]
pub struct BlenvyConfig { pub struct BlenvyConfig {
// registry // registry
@ -29,8 +26,6 @@ pub struct BlenvyConfig {
// save & load // save & load
pub(crate) save_component_filter: SceneFilter, pub(crate) save_component_filter: SceneFilter,
pub(crate) save_resource_filter: SceneFilter, pub(crate) save_resource_filter: SceneFilter,
//pub(crate) save_path: PathBuf,
// save_path: PathBuf::from("saves"),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -68,7 +63,6 @@ impl Plugin for BlenvyPlugin {
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
ExportRegistryPlugin::default(), ExportRegistryPlugin::default(),
BlueprintsPlugin::default(), BlueprintsPlugin::default(),
SaveLoadPlugin::default()
)) ))
.insert_resource(BlenvyConfig { .insert_resource(BlenvyConfig {
export_registry: self.export_registry, export_registry: self.export_registry,

View File

@ -1,59 +1,108 @@
use bevy::prelude::*; pub mod saveable;
use std::path::PathBuf;
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
/// component used to mark any entity as Dynamic: aka add this to make sure your entity is going to be saved
pub struct Dynamic;
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
/// marker component for entities that do not have parents, or whose parents should be ignored when serializing
pub(crate) struct RootEntity;
#[derive(Component, Debug)]
/// internal helper component to store parents before resetting them
pub(crate) struct OriginalParent(pub(crate) Entity);
/// Marker component to Flag the root entity of all static entities (immutables)
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
pub struct StaticEntitiesRoot;
/// Marker component to Flag the root entity of all dynamic entities (mutables)
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
pub struct DynamicEntitiesRoot;
#[derive(Resource, Clone, Debug, Default, Reflect)]
#[reflect(Resource)]
pub struct StaticEntitiesBlueprintInfo {
//pub blueprint_info: BlueprintInfo,
pub path: String,
}
pub use saveable::*;
pub mod saving; pub mod saving;
pub use saving::*; pub use saving::*;
#[derive(Debug, Clone, Default)] pub mod loading;
/// Plugin for saving & loading pub use loading::*;
pub struct SaveLoadPlugin {}
use bevy::core_pipeline::core_3d::{Camera3dDepthTextureUsage, ScreenSpaceTransmissionQuality};
use bevy::prelude::*;
use bevy::prelude::{App, IntoSystemConfigs, Plugin};
use blenvy::GltfBlueprintsSet;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub enum SavingSet {
Save,
}
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub enum LoadingSet {
Load,
}
// Plugin configuration
#[derive(Clone, Resource)]
pub struct SaveLoadConfig {
pub(crate) save_path: PathBuf,
pub(crate) component_filter: SceneFilter,
pub(crate) resource_filter: SceneFilter,
}
// define the plugin
pub struct SaveLoadPlugin {
pub component_filter: SceneFilter,
pub resource_filter: SceneFilter,
pub save_path: PathBuf,
}
impl Default for SaveLoadPlugin {
fn default() -> Self {
Self {
component_filter: SceneFilter::default(),
resource_filter: SceneFilter::default(),
save_path: PathBuf::from("scenes"),
}
}
}
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
pub struct StaticEntitiesRoot;
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
pub struct DynamicEntitiesRoot;
impl Plugin for SaveLoadPlugin { impl Plugin for SaveLoadPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.register_type::<Dynamic>() app.register_type::<Dynamic>()
.register_type::<StaticEntitiesRoot>() .register_type::<StaticEntitiesRoot>()
// TODO: remove these in bevy 0.13, as these are now registered by default
.register_type::<Camera3dDepthTextureUsage>()
.register_type::<ScreenSpaceTransmissionQuality>()
.register_type::<StaticEntitiesStorage>()
.add_event::<SaveRequest>() .add_event::<SaveRequest>()
.add_event::<SaveFinished>() .add_event::<LoadRequest>()
.add_systems( .add_event::<LoadingFinished>()
.add_event::<SavingFinished>()
.insert_resource(SaveLoadConfig {
save_path: self.save_path.clone(),
component_filter: self.component_filter.clone(),
resource_filter: self.resource_filter.clone(),
})
.configure_sets(
Update, Update,
(LoadingSet::Load).chain().before(GltfBlueprintsSet::Spawn), //.before(GltfComponentsSet::Injection)
)
.add_systems(
PreUpdate,
(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_systems(Update, mark_load_requested)
.add_systems(
Update,
(unload_world, apply_deferred, load_game)
.chain()
.run_if(resource_exists::<LoadRequested>)
.run_if(not(resource_exists::<LoadFirstStageDone>))
.in_set(LoadingSet::Load),
)
.add_systems(
Update,
(load_static, apply_deferred, cleanup_loaded_scene)
.chain()
.run_if(resource_exists::<LoadFirstStageDone>)
// .run_if(in_state(AppState::LoadingGame))
.in_set(LoadingSet::Load),
);
} }
} }

View File

@ -1,76 +0,0 @@
pub mod saveable;
use std::path::PathBuf;
pub use saveable::*;
pub mod saving;
pub use saving::*;
pub mod loading;
pub use loading::*;
use bevy::core_pipeline::core_3d::{Camera3dDepthTextureUsage, ScreenSpaceTransmissionQuality};
use bevy::prelude::*;
use bevy::prelude::{App, IntoSystemConfigs, Plugin};
use blenvy::GltfBlueprintsSet;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub enum SavingSet {
Save,
}
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub enum LoadingSet {
Load,
}
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
pub struct StaticEntitiesRoot;
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
pub struct DynamicEntitiesRoot;
impl Plugin for SaveLoadPlugin {
fn build(&self, app: &mut App) {
app.register_type::<Dynamic>()
.register_type::<StaticEntitiesRoot>()
// TODO: remove these in bevy 0.13, as these are now registered by default
.register_type::<Camera3dDepthTextureUsage>()
.register_type::<ScreenSpaceTransmissionQuality>()
.register_type::<StaticEntitiesStorage>()
.add_event::<SaveRequest>()
.add_event::<LoadRequest>()
.add_event::<LoadingFinished>()
.add_event::<SavingFinished>()
.configure_sets(
Update,
(LoadingSet::Load).chain().before(GltfBlueprintsSet::Spawn), //.before(GltfComponentsSet::Injection)
)
.add_systems(
PreUpdate,
(prepare_save_game, apply_deferred, save_game, cleanup_save)
.chain()
.run_if(should_save),
)
.add_systems(Update, mark_load_requested)
.add_systems(
Update,
(unload_world, apply_deferred, load_game)
.chain()
.run_if(resource_exists::<LoadRequested>)
.run_if(not(resource_exists::<LoadFirstStageDone>))
.in_set(LoadingSet::Load),
)
.add_systems(
Update,
(load_static, apply_deferred, cleanup_loaded_scene)
.chain()
.run_if(resource_exists::<LoadFirstStageDone>)
// .run_if(in_state(AppState::LoadingGame))
.in_set(LoadingSet::Load),
);
}
}

View File

@ -1,196 +0,0 @@
use bevy::prelude::*;
use bevy::tasks::IoTaskPool;
use blenvy::{BlueprintName, InBlueprint, Library, SpawnHere};
use std::fs::File;
use std::io::Write;
use std::path::Path;
use crate::{DynamicEntitiesRoot, SaveLoadConfig, StaticEntitiesRoot};
#[derive(Event, Debug)]
pub struct SaveRequest {
pub path: String,
}
#[derive(Event)]
pub struct SavingFinished;
pub fn should_save(save_requests: EventReader<SaveRequest>) -> bool {
!save_requests.is_empty()
}
#[derive(Resource, Clone, Debug, Default, Reflect)]
#[reflect(Resource)]
pub struct StaticEntitiesStorage {
pub name: String,
pub library_path: String,
}
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
/// marker component for entities that do not have parents, or whose parents should be ignored when serializing
pub(crate) struct RootEntity;
#[derive(Component, Debug)]
/// internal helper component to store parents before resetting them
pub(crate) struct OriginalParent(pub(crate) Entity);
// any child of dynamic/ saveable entities that is not saveable itself should be removed from the list of children
pub(crate) fn prepare_save_game(
saveables: Query<Entity, (With<Dynamic>, With<BlueprintName>)>,
root_entities: Query<Entity, Or<(With<DynamicEntitiesRoot>, Without<Parent>)>>, // With<DynamicEntitiesRoot>
dynamic_entities: Query<(Entity, &Parent, Option<&Children>), With<Dynamic>>,
static_entities: Query<(Entity, &BlueprintName, Option<&Library>), With<StaticEntitiesRoot>>,
mut commands: Commands,
) {
for entity in saveables.iter() {
commands.entity(entity).insert(SpawnHere);
}
for (entity, parent, children) in dynamic_entities.iter() {
let parent = parent.get();
if root_entities.contains(parent) {
commands.entity(entity).insert(RootEntity);
}
if let Some(children) = children {
for sub_child in children.iter() {
if !dynamic_entities.contains(*sub_child) {
commands.entity(*sub_child).insert(OriginalParent(entity));
commands.entity(entity).remove_children(&[*sub_child]);
}
}
}
}
for (_, blueprint_name, library) in static_entities.iter() {
let library_path: String = library.map_or_else(|| "", |l| l.0.to_str().unwrap()).into();
commands.insert_resource(StaticEntitiesStorage {
name: blueprint_name.0.clone(),
library_path,
});
}
}
pub(crate) fn save_game(world: &mut World) {
info!("saving");
let mut save_path: String = "".into();
let mut events = world.resource_mut::<Events<SaveRequest>>();
for event in events.get_reader().read(&events) {
info!("SAVE EVENT !! {:?}", event);
save_path.clone_from(&event.path);
}
events.clear();
let saveable_entities: Vec<Entity> = world
.query_filtered::<Entity, (With<Dynamic>, Without<InBlueprint>, Without<RootEntity>)>()
.iter(world)
.collect();
let saveable_root_entities: Vec<Entity> = world
.query_filtered::<Entity, (With<Dynamic>, Without<InBlueprint>, With<RootEntity>)>()
.iter(world)
.collect();
info!("saveable entities {}", saveable_entities.len());
info!("saveable root entities {}", saveable_root_entities.len());
let save_load_config = world
.get_resource::<SaveLoadConfig>()
.expect("SaveLoadConfig should exist at this stage");
// we hardcode some of the always allowed types
let filter = save_load_config
.component_filter
.clone()
.allow::<Parent>()
.allow::<Children>()
.allow::<BlueprintName>()
.allow::<SpawnHere>()
.allow::<Dynamic>()
;
// for root entities, it is the same EXCEPT we make sure parents are not included
let filter_root = filter.clone().deny::<Parent>();
let filter_resources = save_load_config
.resource_filter
.clone()
.allow::<StaticEntitiesStorage>()
;
// for default stuff
let scene_builder = DynamicSceneBuilder::from_world(world)
.with_filter(filter.clone())
.with_resource_filter(filter_resources.clone());
let mut dyn_scene = scene_builder
.extract_resources()
.extract_entities(saveable_entities.clone().into_iter())
.remove_empty_entities()
.build();
// for root entities
let scene_builder_root = DynamicSceneBuilder::from_world(world)
.with_filter(filter_root.clone())
.with_resource_filter(filter_resources.clone());
// FIXME : add back
let mut dyn_scene_root = scene_builder_root
.extract_resources()
.extract_entities(
saveable_root_entities.clone().into_iter(), // .chain(static_world_markers.into_iter()),
)
.remove_empty_entities()
.build();
dyn_scene.entities.append(&mut dyn_scene_root.entities);
// dyn_scene.resources.append(&mut dyn_scene_root.resources);
let serialized_scene = dyn_scene
.serialize(&world.resource::<AppTypeRegistry>().read())
.unwrap();
let save_path = Path::new("assets")
.join(&save_load_config.save_path)
.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);
// world.send_event(SavingFinished);
#[cfg(not(target_arch = "wasm32"))]
IoTaskPool::get()
.spawn(async move {
// Write the scene RON data to file
File::create(save_path)
.and_then(|mut file| file.write(serialized_scene.as_bytes()))
.expect("Error while writing save to file");
})
.detach();
}
pub(crate) fn cleanup_save(
needs_parent_reset: Query<(Entity, &OriginalParent)>,
mut saving_finished: EventWriter<SavingFinished>,
mut commands: Commands,
) {
for (entity, original_parent) in needs_parent_reset.iter() {
commands.entity(original_parent.0).add_child(entity);
}
commands.remove_resource::<StaticEntitiesStorage>();
saving_finished.send(SavingFinished);
}
/*
pub(crate) fn cleanup_save(mut world: &mut World) {
let mut query = world.query::<(Entity, &OriginalParent)>();
for (mut entity, original_parent) in query.iter_mut(&mut world) {
let e = world.entity_mut(original_parent.0);
// .add_child(entity);
}
}*/

View File

@ -0,0 +1,7 @@
use bevy::prelude::*;
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
/// component used to mark any entity as Dynamic: aka add this to make sure your entity is going to be saved
pub struct Dynamic(pub bool);

View File

@ -1,42 +1,55 @@
use bevy::prelude::*;
use bevy::tasks::IoTaskPool;
use blenvy::{BlueprintName, InBlueprint, Library, SpawnHere};
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use bevy::render::camera::{CameraMainTextureUsages, CameraRenderGraph}; use crate::{Dynamic, DynamicEntitiesRoot, SaveLoadConfig, StaticEntitiesRoot};
use bevy::{prelude::*, tasks::IoTaskPool};
use bevy::prelude::World;
use crate::{BlenvyConfig, BlueprintInfo, Dynamic, FromBlueprint, RootEntity, SpawnBlueprint};
use super::{DynamicEntitiesRoot, OriginalParent, StaticEntitiesRoot};
#[derive(Event, Debug)] #[derive(Event, Debug)]
pub struct SaveRequest { pub struct SaveRequest {
pub path: String, pub path: String,
} }
#[derive(Event)] #[derive(Event)]
pub struct SaveFinished; // TODO: merge the the events above pub struct SavingFinished;
pub fn should_save(save_requests: EventReader<SaveRequest>) -> bool { pub fn should_save(save_requests: EventReader<SaveRequest>) -> bool {
!save_requests.is_empty() !save_requests.is_empty()
} }
#[derive(Resource, Clone, Debug, Default, Reflect)]
#[reflect(Resource)]
pub struct StaticEntitiesStorage {
pub name: String,
pub library_path: String,
}
#[derive(Component, Reflect, Debug, Default)]
#[reflect(Component)]
/// marker component for entities that do not have parents, or whose parents should be ignored when serializing
pub(crate) struct RootEntity;
#[derive(Component, Debug)]
/// internal helper component to store parents before resetting them
pub(crate) struct OriginalParent(pub(crate) Entity);
// any child of dynamic/ saveable entities that is not saveable itself should be removed from the list of children // any child of dynamic/ saveable entities that is not saveable itself should be removed from the list of children
pub(crate) fn prepare_save_game( pub(crate) fn prepare_save_game(
saveables: Query<Entity, (With<Dynamic>, With<BlueprintInfo>)>, saveables: Query<Entity, (With<Dynamic>, With<BlueprintName>)>,
root_entities: Query<Entity, Or<(With<DynamicEntitiesRoot>, Without<Parent>)>>, // With<DynamicEntitiesRoot> root_entities: Query<Entity, Or<(With<DynamicEntitiesRoot>, Without<Parent>)>>, // With<DynamicEntitiesRoot>
dynamic_entities: Query<(Entity, &Parent, Option<&Children>), With<Dynamic>>, dynamic_entities: Query<(Entity, &Parent, Option<&Children>), With<Dynamic>>,
static_entities: Query<(Entity, &BlueprintInfo), With<StaticEntitiesRoot>>, static_entities: Query<(Entity, &BlueprintName, Option<&Library>), With<StaticEntitiesRoot>>,
mut commands: Commands, mut commands: Commands,
) { ) {
for entity in saveables.iter() { for entity in saveables.iter() {
commands.entity(entity).insert(SpawnBlueprint); commands.entity(entity).insert(SpawnHere);
} }
for (entity, parent, children) in dynamic_entities.iter() { for (entity, parent, children) in dynamic_entities.iter() {
println!("prepare save game");
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);
@ -51,17 +64,14 @@ pub(crate) fn prepare_save_game(
} }
} }
} }
/*for (_, blueprint_name) in static_entities.iter() { for (_, blueprint_name, library) in static_entities.iter() {
let library_path: String = library.map_or_else(|| "", |l| l.0.to_str().unwrap()).into(); let library_path: String = library.map_or_else(|| "", |l| l.0.to_str().unwrap()).into();
commands.insert_resource(StaticEntitiesStorage { commands.insert_resource(StaticEntitiesStorage {
name: blueprint_name.0.clone(), name: blueprint_name.0.clone(),
library_path, library_path,
}); });
}*/
} }
}
pub(crate) fn save_game(world: &mut World) { pub(crate) fn save_game(world: &mut World) {
info!("saving"); info!("saving");
@ -75,49 +85,39 @@ 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<InBlueprint>, Without<RootEntity>)>()
.query_filtered::<Entity, (With<Dynamic>, 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>, Without<InBlueprint>, With<RootEntity>)>()
//.query_filtered::<Entity, (With<Dynamic>, Without<FromBlueprint>, With<RootEntity>)>()
.iter(world) .iter(world)
.collect(); .collect();
info!("saveable entities {}", saveable_entities.len()); info!("saveable entities {}", saveable_entities.len());
info!("saveable root entities {}", saveable_root_entities.len()); info!("saveable root entities {}", saveable_root_entities.len());
let config = world let save_load_config = world
.get_resource::<BlenvyConfig>() .get_resource::<SaveLoadConfig>()
.expect("Blenvy configuration should exist at this stage"); .expect("SaveLoadConfig should exist at this stage");
// we hardcode some of the always allowed types // we hardcode some of the always allowed types
let filter = config let filter = save_load_config
.save_component_filter .component_filter
.clone() .clone()
.allow::<Parent>() .allow::<Parent>()
.allow::<Children>() .allow::<Children>()
.allow::<BlueprintInfo>() .allow::<BlueprintName>()
.allow::<SpawnBlueprint>() .allow::<SpawnHere>()
.allow::<Dynamic>() .allow::<Dynamic>();
/*.deny::<CameraRenderGraph>()
.deny::<CameraMainTextureUsages>()
.deny::<Handle<Mesh>>()
.deny::<Handle<StandardMaterial>>() */
;
// for root entities, it is the same EXCEPT we make sure parents are not included // for root entities, it is the same EXCEPT we make sure parents are not included
let filter_root = filter.clone().deny::<Parent>(); let filter_root = filter.clone().deny::<Parent>();
let filter_resources = config.clone() let filter_resources = save_load_config
.save_resource_filter .resource_filter
.deny::<Time<Real>>() .clone()
.allow::<StaticEntitiesStorage>();
.clone();
//.allow::<StaticEntitiesStorage>();
// for default stuff // for default stuff
let scene_builder = DynamicSceneBuilder::from_world(world) let scene_builder = DynamicSceneBuilder::from_world(world)
@ -143,15 +143,15 @@ pub(crate) fn save_game(world: &mut World) {
.remove_empty_entities() .remove_empty_entities()
.build(); .build();
// dyn_scene.entities.append(&mut dyn_scene_root.entities); dyn_scene.entities.append(&mut dyn_scene_root.entities);
// dyn_scene.resources.append(&mut dyn_scene_root.resources); // dyn_scene.resources.append(&mut dyn_scene_root.resources);
let serialized_scene = dyn_scene let serialized_scene = dyn_scene
.serialize(&world.resource::<AppTypeRegistry>().read()) .serialize(&world.resource::<AppTypeRegistry>().read())
.expect("filtered scene should serialize correctly"); .unwrap();
let save_path = Path::new("assets") let save_path = Path::new("assets")
//.join(&config.save_path) .join(&save_load_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);
@ -170,12 +170,21 @@ pub(crate) fn save_game(world: &mut World) {
pub(crate) fn cleanup_save( pub(crate) fn cleanup_save(
needs_parent_reset: Query<(Entity, &OriginalParent)>, needs_parent_reset: Query<(Entity, &OriginalParent)>,
mut saving_finished: EventWriter<SaveFinished>, mut saving_finished: EventWriter<SavingFinished>,
mut commands: Commands, mut commands: Commands,
) { ) {
for (entity, original_parent) in needs_parent_reset.iter() { for (entity, original_parent) in needs_parent_reset.iter() {
commands.entity(original_parent.0).add_child(entity); commands.entity(original_parent.0).add_child(entity);
} }
// commands.remove_resource::<StaticEntitiesStorage>(); commands.remove_resource::<StaticEntitiesStorage>();
saving_finished.send(SaveFinished); saving_finished.send(SavingFinished);
} }
/*
pub(crate) fn cleanup_save(mut world: &mut World) {
let mut query = world.query::<(Entity, &OriginalParent)>();
for (mut entity, original_parent) in query.iter_mut(&mut world) {
let e = world.entity_mut(original_parent.0);
// .add_child(entity);
}
}*/

View File

@ -0,0 +1 @@
({})

View File

@ -0,0 +1,8 @@
({
"world":File (path: "models/World.glb"),
"world_dynamic":File (path: "models/World_dynamic.glb"),
"models": Folder (
path: "models/library",
),
})

Binary file not shown.

View File

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

View File

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

View File

@ -1,9 +0,0 @@
(
assets:
[
("Pillar", File ( path: "blueprints/Pillar.glb" )),
("Stone", File ( path: "materials/Stone.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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,14 @@
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, BluePrintBundle, BlueprintInfo, DynamicBlueprintInstance, GameWorldTag, HideUntilReady, SpawnBlueprint};
use rand::Rng; use rand::Rng;
// mod game; mod core;
// use game::*; use crate::core::*;
mod game;
use game::*;
mod component_examples; mod component_examples;
use component_examples::*; use component_examples::*;
@ -34,12 +37,13 @@ fn main() {
..Default::default() ..Default::default()
}, },
// our custom plugins // our custom plugins
// GamePlugin, // specific to our game CorePlugin, // reusable plugins
GamePlugin, // specific to our game
ComponentsExamplesPlugin, // Showcases different type of components /structs ComponentsExamplesPlugin, // Showcases different type of components /structs
)) ))
.add_systems(Startup, setup_game) .add_systems(Startup, setup_game)
.add_systems(Update, (spawn_blueprint_instance, move_movers, save_game, load_game)) .add_systems(Update, (spawn_blueprint_instance, save_game, load_game))
.run(); .run();
} }
@ -56,13 +60,6 @@ fn setup_game(
HideUntilReady, // only reveal the level once it is ready HideUntilReady, // only reveal the level once it is ready
GameWorldTag, 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
));
} }
// you can also spawn blueprint instances at runtime // you can also spawn blueprint instances at runtime
@ -93,47 +90,15 @@ fn spawn_blueprint_instance(
} }
} }
fn move_movers(
mut movers: Query<(&mut Transform), With<Dynamic>>
) {
for mut transform in movers.iter_mut(){
println!("moving dynamic entity");
transform.translation.x += 0.01;
}
}
fn save_game( fn save_game(
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
mut save_requests: EventWriter<SaveRequest>,
) { ) {
if keycode.just_pressed(KeyCode::KeyS) { if keycode.just_pressed(KeyCode::KeyS) {
save_requests.send(SaveRequest {
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>>,
) { ) {

View File

@ -1,14 +1,12 @@
import bpy import bpy
from ...bevy_components.components.metadata import get_bevy_component_value_by_long_name
# checks if an object is dynamic # checks if an object is dynamic
# TODO: for efficiency, it might make sense to write this flag semi automatically at the root level of the object so we can skip the inner loop # TODO: for efficiency, it might make sense to write this flag semi automatically at the root level of the object so we can skip the inner loop
# TODO: we need to recompute these on blueprint changes too # TODO: we need to recompute these on blueprint changes too
# even better, keep a list of dynamic objects per scene , updated only when needed ? # even better, keep a list of dynamic objects per scene , updated only when needed ?
def is_object_dynamic(object): def is_object_dynamic(object):
is_dynamic = get_bevy_component_value_by_long_name(object, 'blenvy::save_load::Dynamic') is not None is_dynamic = object['Dynamic'] if 'Dynamic' in object else False
#is_dynamic = object['Dynamic'] if 'Dynamic' in object else False
# only look for data in the original collection if it is not alread marked as dynamic at instance level # only look for data in the original collection if it is not alread marked as dynamic at instance level
if not is_dynamic and object.type == 'EMPTY' and hasattr(object, 'instance_collection') and object.instance_collection is not None : if not is_dynamic and object.type == 'EMPTY' and hasattr(object, 'instance_collection') and object.instance_collection is not None :
#print("collection", object.instance_collection, "object", object.name) #print("collection", object.instance_collection, "object", object.name)
@ -16,18 +14,15 @@ def is_object_dynamic(object):
collection_name = object.instance_collection.name collection_name = object.instance_collection.name
original_collection = bpy.data.collections[collection_name] original_collection = bpy.data.collections[collection_name]
is_dynamic = get_bevy_component_value_by_long_name(original_collection, 'blenvy::save_load::Dynamic') is not None
# scan original collection, look for a 'Dynamic' flag # scan original collection, look for a 'Dynamic' flag
"""for object in original_collection.objects: for object in original_collection.objects:
#print(" inner", object) #print(" inner", object)
if object.type == 'EMPTY': #and object.name.endswith("components"): if object.type == 'EMPTY' and object.name.endswith("components"):
for component_name in object.keys(): for component_name in object.keys():
#print(" compo", component_name) #print(" compo", component_name)
if component_name == 'Dynamic': if component_name == 'Dynamic':
is_dynamic = True is_dynamic = True
break""" break
print("IS OBJECT DYNAMIC", object, is_dynamic)
return is_dynamic return is_dynamic
def is_object_static(object): def is_object_static(object):

View File

@ -1,8 +1,10 @@
import os import os
import bpy import bpy
from pathlib import Path
from blenvy.core.helpers_collections import (traverse_tree) from blenvy.core.helpers_collections import (traverse_tree)
from blenvy.core.object_makers import make_cube from blenvy.core.object_makers import make_cube
from blenvy.materials.materials_helpers import add_material_info_to_objects, get_all_materials
from ..common.generate_temporary_scene_and_export import generate_temporary_scene_and_export from ..common.generate_temporary_scene_and_export import generate_temporary_scene_and_export
from ..common.export_gltf import (generate_gltf_export_settings) from ..common.export_gltf import (generate_gltf_export_settings)