feat(Blenvy:Bevy): slowly adding back save/load (wip)
* moved out old code * added very basics of saving (HEAVY WIP)
This commit is contained in:
parent
ae9f07f549
commit
171ec7490a
|
@ -10,6 +10,9 @@ 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
|
||||||
|
@ -26,6 +29,8 @@ 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)]
|
||||||
|
@ -63,6 +68,7 @@ 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,
|
||||||
|
|
|
@ -1,108 +1,59 @@
|
||||||
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::*;
|
||||||
use bevy::prelude::{App, IntoSystemConfigs, Plugin};
|
|
||||||
use blenvy::GltfBlueprintsSet;
|
|
||||||
|
|
||||||
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
|
#[derive(Component, Reflect, Debug, Default)]
|
||||||
pub enum SavingSet {
|
#[reflect(Component)]
|
||||||
Save,
|
/// 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(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
|
#[derive(Component, Reflect, Debug, Default)]
|
||||||
pub enum LoadingSet {
|
#[reflect(Component)]
|
||||||
Load,
|
/// marker component for entities that do not have parents, or whose parents should be ignored when serializing
|
||||||
}
|
pub(crate) struct RootEntity;
|
||||||
|
|
||||||
// Plugin configuration
|
#[derive(Component, Debug)]
|
||||||
|
/// internal helper component to store parents before resetting them
|
||||||
|
pub(crate) struct OriginalParent(pub(crate) Entity);
|
||||||
|
|
||||||
#[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"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// Marker component to Flag the root entity of all static entities (immutables)
|
||||||
#[derive(Component, Reflect, Debug, Default)]
|
#[derive(Component, Reflect, Debug, Default)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct StaticEntitiesRoot;
|
pub struct StaticEntitiesRoot;
|
||||||
|
|
||||||
|
/// Marker component to Flag the root entity of all dynamic entities (mutables)
|
||||||
#[derive(Component, Reflect, Debug, Default)]
|
#[derive(Component, Reflect, Debug, Default)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
pub struct DynamicEntitiesRoot;
|
pub struct DynamicEntitiesRoot;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Resource, Clone, Debug, Default, Reflect)]
|
||||||
|
#[reflect(Resource)]
|
||||||
|
pub struct StaticEntitiesBlueprintInfo {
|
||||||
|
//pub blueprint_info: BlueprintInfo,
|
||||||
|
pub path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub mod saving;
|
||||||
|
pub use saving::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
/// Plugin for saving & loading
|
||||||
|
pub struct SaveLoadPlugin {}
|
||||||
|
|
||||||
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::<LoadRequest>()
|
|
||||||
.add_event::<LoadingFinished>()
|
|
||||||
.add_event::<SavingFinished>()
|
|
||||||
.insert_resource(SaveLoadConfig {
|
|
||||||
save_path: self.save_path.clone(),
|
|
||||||
|
|
||||||
component_filter: self.component_filter.clone(),
|
.add_event::<SaveRequest>()
|
||||||
resource_filter: self.resource_filter.clone(),
|
.add_event::<SaveFinished>()
|
||||||
})
|
|
||||||
.configure_sets(
|
|
||||||
Update,
|
|
||||||
(LoadingSet::Load).chain().before(GltfBlueprintsSet::Spawn), //.before(GltfComponentsSet::Injection)
|
|
||||||
)
|
|
||||||
.add_systems(
|
.add_systems(
|
||||||
PreUpdate,
|
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_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),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
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),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,196 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}*/
|
|
@ -1,7 +0,0 @@
|
||||||
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);
|
|
||||||
|
|
|
@ -1,55 +1,42 @@
|
||||||
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 crate::{Dynamic, DynamicEntitiesRoot, SaveLoadConfig, StaticEntitiesRoot};
|
use bevy::render::camera::{CameraMainTextureUsages, CameraRenderGraph};
|
||||||
|
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 SavingFinished;
|
pub struct SaveFinished; // TODO: merge the the events above
|
||||||
|
|
||||||
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<BlueprintName>)>,
|
saveables: Query<Entity, (With<Dynamic>, With<BlueprintInfo>)>,
|
||||||
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, &BlueprintName, Option<&Library>), With<StaticEntitiesRoot>>,
|
static_entities: Query<(Entity, &BlueprintInfo), With<StaticEntitiesRoot>>,
|
||||||
|
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
) {
|
||||||
for entity in saveables.iter() {
|
for entity in saveables.iter() {
|
||||||
commands.entity(entity).insert(SpawnHere);
|
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");
|
||||||
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);
|
||||||
|
@ -64,14 +51,17 @@ pub(crate) fn prepare_save_game(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (_, blueprint_name, library) in static_entities.iter() {
|
/*for (_, blueprint_name) 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");
|
||||||
|
|
||||||
|
@ -85,39 +75,49 @@ 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<InBlueprint>, Without<RootEntity>)>()
|
// .query_filtered::<Entity, (With<Dynamic>, Without<FromBlueprint>, 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>, Without<InBlueprint>, With<RootEntity>)>()
|
.query_filtered::<Entity, (With<Dynamic>, 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 save_load_config = world
|
let config = world
|
||||||
.get_resource::<SaveLoadConfig>()
|
.get_resource::<BlenvyConfig>()
|
||||||
.expect("SaveLoadConfig should exist at this stage");
|
.expect("Blenvy configuration should exist at this stage");
|
||||||
|
|
||||||
// we hardcode some of the always allowed types
|
// we hardcode some of the always allowed types
|
||||||
let filter = save_load_config
|
let filter = config
|
||||||
.component_filter
|
.save_component_filter
|
||||||
.clone()
|
.clone()
|
||||||
.allow::<Parent>()
|
.allow::<Parent>()
|
||||||
.allow::<Children>()
|
.allow::<Children>()
|
||||||
.allow::<BlueprintName>()
|
.allow::<BlueprintInfo>()
|
||||||
.allow::<SpawnHere>()
|
.allow::<SpawnBlueprint>()
|
||||||
.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 = save_load_config
|
let filter_resources = config.clone()
|
||||||
.resource_filter
|
.save_resource_filter
|
||||||
.clone()
|
.deny::<Time<Real>>()
|
||||||
.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())
|
||||||
.unwrap();
|
.expect("filtered scene should serialize correctly");
|
||||||
|
|
||||||
let save_path = Path::new("assets")
|
let save_path = Path::new("assets")
|
||||||
.join(&save_load_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);
|
||||||
|
|
||||||
|
@ -170,21 +170,12 @@ 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<SavingFinished>,
|
mut saving_finished: EventWriter<SaveFinished>,
|
||||||
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(SavingFinished);
|
saving_finished.send(SaveFinished);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
Loading…
Reference in New Issue