mirror of
https://github.com/kaosat-dev/Blender_bevy_components_workflow.git
synced 2024-11-24 12:50:53 +00:00
Compare commits
5 Commits
18b4c50ee5
...
cb95e7fb57
Author | SHA1 | Date | |
---|---|---|---|
|
cb95e7fb57 | ||
|
c4d8e02a9d | ||
|
e573251707 | ||
|
bd830e5ad4 | ||
|
0b02a24313 |
17
TODO.md
17
TODO.md
@ -259,6 +259,23 @@ Blender side:
|
|||||||
- [x] make sure the "add scene" button is not available unless you have actually selected one
|
- [x] make sure the "add scene" button is not available unless you have actually selected one
|
||||||
- [x] make auto export be on by default, however bail out early by detecting if there are any level/blueprint scenes
|
- [x] make auto export be on by default, however bail out early by detecting if there are any level/blueprint scenes
|
||||||
- [x] remove custom components to filter out correctly from exported blueprints list
|
- [x] remove custom components to filter out correctly from exported blueprints list
|
||||||
|
- [ ] for built in Component types that need to be injected to be used by blueprints,
|
||||||
|
namely:
|
||||||
|
- BlueprintInfos (not 100% sure for this one)
|
||||||
|
- MaterialInfos
|
||||||
|
- the various scene Components
|
||||||
|
- BlueprintAssets (although not really needed anymore with the meta files)
|
||||||
|
|
||||||
|
- [ ] Inject real components instead of just custom properties
|
||||||
|
- [ ] add boilerplate to generate real component values from type definitions instead of hacking pseudo ron strings
|
||||||
|
- [ ] fall back to bevy_components if that fails (missing registry) or just basic custom properties
|
||||||
|
- [ ] If that fails as well ?
|
||||||
|
- [ ] auto reload registry if absent/possible
|
||||||
|
- cannot be done from UI possibly polling with increasing timeout
|
||||||
|
- bpy.ops.blenvy.components_registry_reload()
|
||||||
|
|
||||||
|
- [x] filter out MaterialInfos from list of "fixable components"
|
||||||
|
|
||||||
|
|
||||||
Bevy Side:
|
Bevy Side:
|
||||||
- [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead
|
- [x] deprecate BlueprintName & BlueprintPath & use BlueprintInfo instead
|
||||||
|
@ -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(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
45
crates/blenvy/src/save_load/common.rs
Normal file
45
crates/blenvy/src/save_load/common.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
118
crates/blenvy/src/save_load/loading.rs
Normal file
118
crates/blenvy/src/save_load/loading.rs
Normal 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>();
|
||||||
|
}
|
@ -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),
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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(
|
||||||
|
@ -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);
|
||||||
|
@ -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>();
|
||||||
|
|
||||||
}
|
}
|
@ -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"}
|
Binary file not shown.
1
examples/save_load/assets/.save.ron
Normal file
1
examples/save_load/assets/.save.ron
Normal file
@ -0,0 +1 @@
|
|||||||
|
(dynamic: assets/, static: levels/world.glb)
|
BIN
examples/save_load/assets/blueprints/Dynamic_hierarchy.glb
Normal file
BIN
examples/save_load/assets/blueprints/Dynamic_hierarchy.glb
Normal file
Binary file not shown.
@ -0,0 +1,5 @@
|
|||||||
|
(
|
||||||
|
assets:
|
||||||
|
[
|
||||||
|
]
|
||||||
|
)
|
BIN
examples/save_load/assets/blueprints/Dynamic_inside_static.glb
Normal file
BIN
examples/save_load/assets/blueprints/Dynamic_inside_static.glb
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
(
|
||||||
|
assets:
|
||||||
|
[
|
||||||
|
("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.
@ -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.
BIN
examples/save_load/assets/materials/Dots Stroke.glb
Normal file
BIN
examples/save_load/assets/materials/Dots Stroke.glb
Normal file
Binary file not shown.
BIN
examples/save_load/assets/materials/Material.001.glb
Normal file
BIN
examples/save_load/assets/materials/Material.001.glb
Normal file
Binary file not shown.
BIN
examples/save_load/assets/materials/Stone.glb
Normal file
BIN
examples/save_load/assets/materials/Stone.glb
Normal file
Binary file not shown.
@ -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,
|
||||||
|
@ -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),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
1
examples/save_load/assets/scenes/save.scn.ron.save.ron
Normal file
1
examples/save_load/assets/scenes/save.scn.ron.save.ron
Normal file
@ -0,0 +1 @@
|
|||||||
|
(dynamic: assets/scenes/save.scn.ron, static: levels/world.glb)
|
@ -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(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"}
|
@ -54,6 +54,7 @@ def generate_temporary_scene_and_export(settings, gltf_export_settings, gltf_out
|
|||||||
else:
|
else:
|
||||||
set_active_collection(bpy.context.scene, temp_root_collection.name)
|
set_active_collection(bpy.context.scene, temp_root_collection.name)
|
||||||
# generate contents of temporary scene
|
# generate contents of temporary scene
|
||||||
|
|
||||||
scene_filler_data = tempScene_filler(temp_root_collection)
|
scene_filler_data = tempScene_filler(temp_root_collection)
|
||||||
# export the temporary scene
|
# export the temporary scene
|
||||||
try:
|
try:
|
||||||
|
@ -3,7 +3,6 @@ import bpy
|
|||||||
from ...bevy_components.components.metadata import get_bevy_component_value_by_long_name
|
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: 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):
|
||||||
@ -15,18 +14,10 @@ def is_object_dynamic(object):
|
|||||||
# get the name of the collection this is an instance of
|
# get the name of the collection this is an instance of
|
||||||
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:
|
is_dynamic = get_bevy_component_value_by_long_name(original_collection, 'blenvy::save_load::Dynamic') is not None
|
||||||
#print(" inner", object)
|
|
||||||
if object.type == 'EMPTY': #and object.name.endswith("components"):
|
#print("IS OBJECT DYNAMIC", object, is_dynamic)
|
||||||
for component_name in object.keys():
|
|
||||||
#print(" compo", component_name)
|
|
||||||
if component_name == 'Dynamic':
|
|
||||||
is_dynamic = True
|
|
||||||
break"""
|
|
||||||
print("IS OBJECT DYNAMIC", object, is_dynamic)
|
|
||||||
|
|
||||||
return is_dynamic
|
return is_dynamic
|
||||||
|
|
||||||
|
@ -15,9 +15,10 @@ def get_materials_to_export(changes_per_material, changed_export_parameters, blu
|
|||||||
local_materials = [material for material in all_materials if material.library is None]
|
local_materials = [material for material in all_materials if material.library is None]
|
||||||
materials_to_export = []
|
materials_to_export = []
|
||||||
|
|
||||||
|
# print("export_materials_library", export_materials_library, "change detection", change_detection, "changed_export_parameters", changed_export_parameters)
|
||||||
if export_materials_library and change_detection:
|
if export_materials_library and change_detection:
|
||||||
if changed_export_parameters:
|
if changed_export_parameters:
|
||||||
materials_to_export = [bpy.data.materials[material_name] for material_name in list(changes_per_material.keys())] # TODO: should be based on the list of materials in use
|
materials_to_export = local_materials
|
||||||
else :
|
else :
|
||||||
changed_materials = [bpy.data.materials[material_name] for material_name in list(changes_per_material.keys())]
|
changed_materials = [bpy.data.materials[material_name] for material_name in list(changes_per_material.keys())]
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ from ..utils import get_selected_item, get_selection_type
|
|||||||
from .metadata import do_item_custom_properties_have_missing_metadata, get_bevy_components
|
from .metadata import do_item_custom_properties_have_missing_metadata, get_bevy_components
|
||||||
|
|
||||||
|
|
||||||
def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_type="OBJECT", item_name=""):
|
def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_type="OBJECT", item_name="", enabled=True):
|
||||||
is_enum = getattr(propertyGroup, "with_enum")
|
is_enum = getattr(propertyGroup, "with_enum")
|
||||||
is_list = getattr(propertyGroup, "with_list")
|
is_list = getattr(propertyGroup, "with_list")
|
||||||
is_map = getattr(propertyGroup, "with_map")
|
is_map = getattr(propertyGroup, "with_map")
|
||||||
@ -13,6 +13,7 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
|
|||||||
|
|
||||||
# if it is an enum, the first field name is always the list of enum variants, the others are the variants
|
# if it is an enum, the first field name is always the list of enum variants, the others are the variants
|
||||||
field_names = propertyGroup.field_names
|
field_names = propertyGroup.field_names
|
||||||
|
layout.enabled = enabled
|
||||||
#print("")
|
#print("")
|
||||||
#print("drawing", propertyGroup, nesting, "component_name", rootName)
|
#print("drawing", propertyGroup, nesting, "component_name", rootName)
|
||||||
if is_enum:
|
if is_enum:
|
||||||
@ -31,7 +32,7 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
|
|||||||
nested = getattr(nestedPropertyGroup, "nested", False)
|
nested = getattr(nestedPropertyGroup, "nested", False)
|
||||||
#print("nestedPropertyGroup", nestedPropertyGroup, fname, nested)
|
#print("nestedPropertyGroup", nestedPropertyGroup, fname, nested)
|
||||||
if nested:
|
if nested:
|
||||||
draw_propertyGroup(nestedPropertyGroup, subrow.column(), nesting + [fname], rootName, item_type, item_name )
|
draw_propertyGroup(nestedPropertyGroup, subrow.column(), nesting + [fname], rootName, item_type, item_name, enabled=enabled )
|
||||||
# if an enum variant is not a propertyGroup
|
# if an enum variant is not a propertyGroup
|
||||||
break
|
break
|
||||||
elif is_list:
|
elif is_list:
|
||||||
@ -39,12 +40,13 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
|
|||||||
list_index = getattr(propertyGroup, "list_index")
|
list_index = getattr(propertyGroup, "list_index")
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
split = box.split(factor=0.9)
|
split = box.split(factor=0.9)
|
||||||
|
box.enabled = enabled
|
||||||
list_column, buttons_column = (split.column(),split.column())
|
list_column, buttons_column = (split.column(),split.column())
|
||||||
|
|
||||||
list_column = list_column.box()
|
list_column = list_column.box()
|
||||||
for index, item in enumerate(item_list):
|
for index, item in enumerate(item_list):
|
||||||
row = list_column.row()
|
row = list_column.row()
|
||||||
draw_propertyGroup(item, row, nesting, rootName, item_type)
|
draw_propertyGroup(item, row, nesting, rootName, item_type, enabled=enabled)
|
||||||
icon = 'CHECKBOX_HLT' if list_index == index else 'CHECKBOX_DEHLT'
|
icon = 'CHECKBOX_HLT' if list_index == index else 'CHECKBOX_DEHLT'
|
||||||
op = row.operator('blenvy.component_list_actions', icon=icon, text="")
|
op = row.operator('blenvy.component_list_actions', icon=icon, text="")
|
||||||
op.action = 'SELECT'
|
op.action = 'SELECT'
|
||||||
@ -100,10 +102,10 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
|
|||||||
row = box.row()
|
row = box.row()
|
||||||
row.label(text="Add entry:")
|
row.label(text="Add entry:")
|
||||||
keys_setter = getattr(propertyGroup, "keys_setter")
|
keys_setter = getattr(propertyGroup, "keys_setter")
|
||||||
draw_propertyGroup(keys_setter, row, nesting, rootName, item_type, item_name)
|
draw_propertyGroup(keys_setter, row, nesting, rootName, item_type, item_name, enabled=enabled)
|
||||||
|
|
||||||
values_setter = getattr(propertyGroup, "values_setter")
|
values_setter = getattr(propertyGroup, "values_setter")
|
||||||
draw_propertyGroup(values_setter, row, nesting, rootName, item_type, item_name)
|
draw_propertyGroup(values_setter, row, nesting, rootName, item_type, item_name, enabled=enabled)
|
||||||
|
|
||||||
op = row.operator('blenvy.component_map_actions', icon='ADD', text="")
|
op = row.operator('blenvy.component_map_actions', icon='ADD', text="")
|
||||||
op.action = 'ADD'
|
op.action = 'ADD'
|
||||||
@ -119,10 +121,10 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
|
|||||||
|
|
||||||
for index, item in enumerate(keys_list):
|
for index, item in enumerate(keys_list):
|
||||||
row = list_column.row()
|
row = list_column.row()
|
||||||
draw_propertyGroup(item, row, nesting, rootName, item_type, item_name)
|
draw_propertyGroup(item, row, nesting, rootName, item_type, item_name, enabled=enabled)
|
||||||
|
|
||||||
value = values_list[index]
|
value = values_list[index]
|
||||||
draw_propertyGroup(value, row, nesting, rootName, item_type, item_name)
|
draw_propertyGroup(value, row, nesting, rootName, item_type, item_name, enabled=enabled)
|
||||||
|
|
||||||
op = row.operator('blenvy.component_map_actions', icon='REMOVE', text="")
|
op = row.operator('blenvy.component_map_actions', icon='REMOVE', text="")
|
||||||
op.action = 'REMOVE'
|
op.action = 'REMOVE'
|
||||||
@ -151,7 +153,7 @@ def draw_propertyGroup( propertyGroup, layout, nesting =[], rootName=None, item_
|
|||||||
layout.label(text=display_name) # this is the name of the field/sub field
|
layout.label(text=display_name) # this is the name of the field/sub field
|
||||||
layout.separator()
|
layout.separator()
|
||||||
subrow = layout.row()
|
subrow = layout.row()
|
||||||
draw_propertyGroup(nestedPropertyGroup, subrow, nesting + [fname], rootName, item_type, item_name )
|
draw_propertyGroup(nestedPropertyGroup, subrow, nesting + [fname], rootName, item_type, item_name, enabled )
|
||||||
else:
|
else:
|
||||||
subrow = layout.row()
|
subrow = layout.row()
|
||||||
subrow.prop(propertyGroup, fname, text=display_name)
|
subrow.prop(propertyGroup, fname, text=display_name)
|
||||||
@ -233,6 +235,9 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
|
|||||||
item_name = object_or_collection.name
|
item_name = object_or_collection.name
|
||||||
#print("components_names", dict(components_bla).keys())
|
#print("components_names", dict(components_bla).keys())
|
||||||
|
|
||||||
|
#FIXME: move out, highly inneficient
|
||||||
|
internal_components = ['BlueprintInfos', 'blenvy::blueprints::materials::MaterialInfos']
|
||||||
|
|
||||||
for component_name in sorted(get_bevy_components(object_or_collection)) : # sorted by component name, practical
|
for component_name in sorted(get_bevy_components(object_or_collection)) : # sorted by component name, practical
|
||||||
if component_name == "components_meta":
|
if component_name == "components_meta":
|
||||||
continue
|
continue
|
||||||
@ -244,7 +249,9 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
|
|||||||
component_invalid = getattr(component_meta, "invalid")
|
component_invalid = getattr(component_meta, "invalid")
|
||||||
invalid_details = getattr(component_meta, "invalid_details")
|
invalid_details = getattr(component_meta, "invalid_details")
|
||||||
component_visible = getattr(component_meta, "visible")
|
component_visible = getattr(component_meta, "visible")
|
||||||
|
component_internal = component_name in internal_components # internal components are not editable ?
|
||||||
single_field = False
|
single_field = False
|
||||||
|
label = f"{component_name}{' (internal)' if component_internal else ''}"
|
||||||
|
|
||||||
# our whole row
|
# our whole row
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
@ -252,7 +259,8 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
|
|||||||
# "header"
|
# "header"
|
||||||
row.alert = component_invalid
|
row.alert = component_invalid
|
||||||
row.prop(component_meta, "enabled", text="")
|
row.prop(component_meta, "enabled", text="")
|
||||||
row.label(text=component_name)
|
row.label(text=label)
|
||||||
|
#row.enabled = not component_internal
|
||||||
|
|
||||||
# we fetch the matching ui property group
|
# we fetch the matching ui property group
|
||||||
root_propertyGroup_name = registry.get_propertyGroupName_from_longName(component_name)
|
root_propertyGroup_name = registry.get_propertyGroupName_from_longName(component_name)
|
||||||
@ -272,7 +280,7 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
|
|||||||
error_message = invalid_details if component_invalid else "Missing component UI data, please reload registry !"
|
error_message = invalid_details if component_invalid else "Missing component UI data, please reload registry !"
|
||||||
prop_group_location.label(text=error_message)
|
prop_group_location.label(text=error_message)
|
||||||
else:
|
else:
|
||||||
draw_propertyGroup(propertyGroup, prop_group_location, [root_propertyGroup_name], component_name, item_type, item_name)
|
draw_propertyGroup(propertyGroup, prop_group_location, [root_propertyGroup_name], component_name, item_type, item_name, enabled=not component_internal)
|
||||||
else :
|
else :
|
||||||
row.label(text="details hidden, click on toggle to display")
|
row.label(text="details hidden, click on toggle to display")
|
||||||
else:
|
else:
|
||||||
@ -293,17 +301,18 @@ def draw_component_ui(layout, object_or_collection, registry, selected_component
|
|||||||
op.component_name = component_name
|
op.component_name = component_name
|
||||||
row.separator()
|
row.separator()
|
||||||
|
|
||||||
op = row.operator("blenvy.component_remove", text="", icon="X")
|
if not component_internal:
|
||||||
op.component_name = component_name
|
op = row.operator("blenvy.component_remove", text="", icon="X")
|
||||||
op.item_name = object_or_collection.name
|
op.component_name = component_name
|
||||||
op.item_type = get_selection_type(object_or_collection)
|
op.item_name = object_or_collection.name
|
||||||
row.separator()
|
op.item_type = get_selection_type(object_or_collection)
|
||||||
|
row.separator()
|
||||||
op = row.operator("blenvy.component_copy", text="", icon="COPYDOWN")
|
|
||||||
op.source_component_name = component_name
|
op = row.operator("blenvy.component_copy", text="", icon="COPYDOWN")
|
||||||
op.source_item_name = object_or_collection.name
|
op.source_component_name = component_name
|
||||||
op.source_item_type = get_selection_type(object_or_collection)
|
op.source_item_name = object_or_collection.name
|
||||||
row.separator()
|
op.source_item_type = get_selection_type(object_or_collection)
|
||||||
|
row.separator()
|
||||||
|
|
||||||
#if not single_field:
|
#if not single_field:
|
||||||
toggle_icon = "TRIA_DOWN" if component_visible else "TRIA_RIGHT"
|
toggle_icon = "TRIA_DOWN" if component_visible else "TRIA_RIGHT"
|
||||||
@ -388,7 +397,7 @@ class BLENVY_PT_component_tools_panel(bpy.types.Panel):
|
|||||||
self.draw_invalid_or_unregistered(layout, status, custom_property, item, item_type)
|
self.draw_invalid_or_unregistered(layout, status, custom_property, item, item_type)
|
||||||
|
|
||||||
def gather_invalid_item_data(self, item, invalid_component_names, items_with_invalid_components, items_with_original_components, original_name, item_type):
|
def gather_invalid_item_data(self, item, invalid_component_names, items_with_invalid_components, items_with_original_components, original_name, item_type):
|
||||||
blenvy_custom_properties = ['components_meta', 'bevy_components', 'user_assets', 'generated_assets', 'BlueprintAssets', 'export_path' ] # some of our own hard coded custom properties that should be ignored
|
blenvy_custom_properties = ['components_meta', 'bevy_components', 'user_assets', 'generated_assets', 'BlueprintAssets', 'export_path', 'MaterialInfos' ] # some of our own hard coded custom properties that should be ignored
|
||||||
upgreadable_entries = []
|
upgreadable_entries = []
|
||||||
|
|
||||||
if "components_meta" in item or hasattr(item, "components_meta"): # FIXME; wrong way of determining
|
if "components_meta" in item or hasattr(item, "components_meta"): # FIXME; wrong way of determining
|
||||||
|
@ -32,6 +32,7 @@ def watch_schema():
|
|||||||
blenvy = bpy.context.window_manager.blenvy
|
blenvy = bpy.context.window_manager.blenvy
|
||||||
component_settings = blenvy.components
|
component_settings = blenvy.components
|
||||||
#print("watching schema file for changes")
|
#print("watching schema file for changes")
|
||||||
|
reloading_registry = False
|
||||||
try:
|
try:
|
||||||
stamp = os.stat(component_settings.schema_path_full).st_mtime
|
stamp = os.stat(component_settings.schema_path_full).st_mtime
|
||||||
stamp = str(stamp)
|
stamp = str(stamp)
|
||||||
@ -47,11 +48,19 @@ def watch_schema():
|
|||||||
# we need to add an additional delay as the file might not have loaded yet
|
# we need to add an additional delay as the file might not have loaded yet
|
||||||
bpy.app.timers.register(lambda: bpy.ops.blenvy.components_registry_reload(), first_interval=1)
|
bpy.app.timers.register(lambda: bpy.ops.blenvy.components_registry_reload(), first_interval=1)
|
||||||
component_settings.schemaTimeStamp = stamp
|
component_settings.schemaTimeStamp = stamp
|
||||||
|
reloading_registry = True
|
||||||
|
|
||||||
if component_settings.schemaTimeStamp == "":
|
if component_settings.schemaTimeStamp == "":
|
||||||
component_settings.schemaTimeStamp = stamp
|
component_settings.schemaTimeStamp = stamp
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# if there is no registry loaded yet, try to load it
|
||||||
|
"""registry = bpy.context.window_manager.components_registry
|
||||||
|
if not reloading_registry and len(list(registry.type_infos.keys())) == 0:
|
||||||
|
print("reload registry here")
|
||||||
|
bpy.app.timers.register(lambda: bpy.ops.blenvy.components_registry_reload(), first_interval=1)"""
|
||||||
|
|
||||||
return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None
|
return component_settings.watcher_poll_frequency if component_settings.watcher_enabled else None
|
||||||
|
|
||||||
class ComponentsSettings(PropertyGroup):
|
class ComponentsSettings(PropertyGroup):
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import posixpath
|
import posixpath
|
||||||
from ..core.helpers_collections import (traverse_tree)
|
from ..core.helpers_collections import (traverse_tree)
|
||||||
|
from ..add_ons.bevy_components.components.metadata import apply_propertyGroup_values_to_item_customProperties_for_component, upsert_bevy_component, get_bevy_component_value_by_long_name
|
||||||
|
|
||||||
def find_materials_not_on_disk(materials, materials_path_full, extension):
|
def find_materials_not_on_disk(materials, materials_path_full, extension):
|
||||||
not_found_materials = []
|
not_found_materials = []
|
||||||
@ -79,6 +80,7 @@ def get_all_materials(collection_names, library_scenes):
|
|||||||
used_material_names = list(set(used_material_names))
|
used_material_names = list(set(used_material_names))
|
||||||
return (used_material_names, materials_per_object)
|
return (used_material_names, materials_per_object)
|
||||||
|
|
||||||
|
import bpy
|
||||||
def add_material_info_to_objects(materials_per_object, settings):
|
def add_material_info_to_objects(materials_per_object, settings):
|
||||||
materials_path = getattr(settings, "materials_path")
|
materials_path = getattr(settings, "materials_path")
|
||||||
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
|
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
|
||||||
@ -90,8 +92,13 @@ def add_material_info_to_objects(materials_per_object, settings):
|
|||||||
material_infos.append(material_info)
|
material_infos.append(material_info)
|
||||||
# problem with using actual components: you NEED the type registry/component infos, so if there is none , or it is not loaded yet, it does not work
|
# problem with using actual components: you NEED the type registry/component infos, so if there is none , or it is not loaded yet, it does not work
|
||||||
# for a few components we could hardcode this
|
# for a few components we could hardcode this
|
||||||
#bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value)
|
component_value = f"({material_infos})".replace("'","")
|
||||||
object['MaterialInfos'] = f"({material_infos})".replace("'","")
|
try:
|
||||||
|
bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value )
|
||||||
|
except:
|
||||||
|
object['MaterialInfos'] = f"({material_infos})".replace("'","")
|
||||||
|
#upsert_bevy_component(object, "blenvy::blueprints::materials::MaterialInfos", f"({material_infos})".replace("'","") )
|
||||||
|
#apply_propertyGroup_values_to_item_customProperties_for_component(object, "MaterialInfos")
|
||||||
print("adding materialInfos to object", object, "material infos", material_infos)
|
print("adding materialInfos to object", object, "material infos", material_infos)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user