From e3c81f2b3e66a05dc3060c86f520e41028963d72 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 19:52:27 +0300 Subject: [PATCH 01/35] Fix compilation with bevy 0.12 Only compilation, many bugs exists --- Cargo.toml | 25 +++++----- src/editor/core/gltf_unpack.rs | 11 +++-- src/editor/core/load.rs | 4 +- src/editor/mod.rs | 57 ++++++++++++++++------- src/editor/ui/hierarchy.rs | 2 +- src/editor/ui/inspector/mod.rs | 26 ++++++++--- src/editor/ui/mod.rs | 2 +- src/editor_registry/mod.rs | 4 +- src/lib.rs | 15 ++---- src/optional/bevy_xpbd_plugin/collider.rs | 18 +++---- src/prefab/component/mod.rs | 2 +- src/prefab/load.rs | 3 +- src/prefab/mod.rs | 18 +++---- src/prefab/save.rs | 2 +- 14 files changed, 109 insertions(+), 80 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bc2f60ba..a597bbb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,19 +13,20 @@ homepage = "https://github.com/rewin123/space_editor" repository = "https://github.com/rewin123/space_editor" [dependencies] -bevy = "0.11" -bevy_egui = "0.21" -egui-gizmo = "0.11.0" -bevy-scene-hook = "7" -ron = "0.8.0" -bevy_panorbit_camera = "0.7.0" -bevy-inspector-egui = {version = "0.19.0", features = ["bevy_pbr", "highlight_changes"]} -bevy_mod_picking = {version = "0.15.0", features = ["backend_egui"]} -bevy_infinite_grid = "0.8.1" -egui_dock = "0.7" -egui_file = "0.10.2" +bevy = "0.12" +bevy_egui = "0.23" +egui-gizmo = "0.12" +bevy-scene-hook = "9" +ron = "0.8" +bevy_panorbit_camera = {version = "0.9", features=["bevy_egui"]} +bevy-inspector-egui = {version = "0.21", features = ["bevy_pbr", "highlight_changes"]} +pretty-type-name = "1.0" +bevy_mod_picking = {version = "0.17", features = ["backend_egui"]} +bevy_debug_grid = "0.3" +egui_dock = "0.8" +egui_file = "0.11" -bevy_xpbd_3d = {git = "https://github.com/Jondolf/bevy_xpbd.git", rev = "2e257b2910233af44a5f6571f4cb0c3817d010f0", default-features = false, optional = true} +bevy_xpbd_3d = {version="0.3", default-features = false, optional = true} [profile.dev.package.bevy_xpbd_3d] opt-level = 3 diff --git a/src/editor/core/gltf_unpack.rs b/src/editor/core/gltf_unpack.rs index 18b80aa5..f1c7b7a0 100644 --- a/src/editor/core/gltf_unpack.rs +++ b/src/editor/core/gltf_unpack.rs @@ -60,7 +60,7 @@ fn queue_push( mut events: EventWriter, assets: Res, ) { - if !queue.0.is_empty() && assets.get_load_state(&queue.0[0]) == LoadState::Loaded { + if !queue.0.is_empty() && assets.get_load_state(&queue.0[0]) == Some(LoadState::Loaded) { events.send(GltfLoaded(queue.0.remove(0))); } } @@ -84,10 +84,11 @@ fn unpack_gltf(world: &mut World) { let mut command_queue = CommandQueue::default(); for gltf in loaded_scenes.iter() { let handle: Handle = gltf.0.clone(); - let gltf_path = world - .resource::() - .get_handle_path(&handle) - .unwrap(); + let gltf_path= if let Some(path) = handle.path() { + path.clone() + } else { + continue; + }; info!("Path: {:?}", &gltf_path); let Some(gltf) = world.resource::>().get(&gltf.0) else { diff --git a/src/editor/core/load.rs b/src/editor/core/load.rs index fe5a47e3..8412de1b 100644 --- a/src/editor/core/load.rs +++ b/src/editor/core/load.rs @@ -1,4 +1,4 @@ -use bevy::{ecs::entity::EntityMap, prelude::*}; +use bevy::{prelude::*, utils::HashMap}; use crate::{prelude::EditorLoader, PrefabMarker}; @@ -34,7 +34,7 @@ pub fn load_listener(world: &mut World) { entity.components.push(Box::new(PrefabMarker)); } - let mut map = EntityMap::default(); + let mut map = HashMap::new(); let res = prefab.write_to_world(world, &mut map); match res { Ok(_) => { /*some info planned*/ } diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 723e8f38..6732e81f 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -1,6 +1,6 @@ //code only for editor gui -use bevy::{prelude::*, window::PrimaryWindow}; +use bevy::{prelude::*, window::PrimaryWindow, render::render_resource::PrimitiveTopology}; pub mod core; pub mod ui; @@ -8,9 +8,8 @@ pub mod ui; pub mod ui_registration; use bevy_egui::{EguiContext, EguiContexts}; -use bevy_infinite_grid::{InfiniteGrid, InfiniteGridBundle}; use bevy_inspector_egui::{quick::WorldInspectorPlugin, DefaultInspectorConfigPlugin}; -use bevy_mod_picking::{prelude::*, PickableBundle}; +use bevy_mod_picking::{prelude::*, PickableBundle, backends::raycast::bevy_mod_raycast::prelude::RaycastSettings}; use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraSystemSet}; use crate::{ @@ -53,10 +52,12 @@ impl Plugin for EditorPlugin { .disable::() .disable::(), ); + + app.world.resource_mut::().require_markers = true; } - if !app.is_plugin_added::() { - app.add_plugins(bevy_infinite_grid::InfiniteGridPlugin); + if !app.is_plugin_added::() { + app.add_plugins(bevy_debug_grid::DebugGridPlugin::without_floor_grid()); } app.init_resource::(); @@ -113,10 +114,12 @@ impl Plugin for EditorPlugin { ( auto_add_picking, select_listener.after(UiSystemSet), - auto_add_picking_dummy, ) .run_if(in_state(EditorState::Editor)), ); + app.add_systems( + PostUpdate, + auto_add_picking_dummy); app.add_systems( Update, @@ -142,10 +145,10 @@ struct SelectEvent { } fn create_grid_lines(mut commands: Commands) { - commands.spawn(InfiniteGridBundle::default()); + bevy_debug_grid::spawn_floor_grid(commands); } -fn cleanup_grid_lines(mut commands: Commands, query: Query>) { +fn cleanup_grid_lines(mut commands: Commands, query: Query>) { for e in query.iter() { commands.entity(e).despawn_recursive(); } @@ -159,19 +162,30 @@ fn auto_add_picking( commands .entity(e) .insert(PickableBundle::default()) - .insert(RaycastPickTarget::default()) .insert(On::>::send_event::()); } } -type AutoAddQueryFilter = (Without, Without, With); - -fn auto_add_picking_dummy(mut commands: Commands, query: Query) { - for e in query.iter() { - commands - .entity(e) - .insert(PickableBundle::default()) - .insert(RaycastPickTarget::default()); +type AutoAddQueryFilter = ( + Without, + Without, + With, + Changed>); + +//Auto add picking for each child to propagate picking event up to prefab entitiy +fn auto_add_picking_dummy( + mut commands: Commands, + query : Query<(Entity, &Handle), AutoAddQueryFilter>, + meshs : Res>) { + for (e, mesh) in query.iter() { + //Only meshed entity need to be pickable + if let Some(mesh) = meshs.get(mesh) { + if mesh.primitive_topology() == PrimitiveTopology::TriangleList { + commands + .entity(e) + .insert(PickableBundle::default()); + } + } } } @@ -370,3 +384,12 @@ fn draw_camera_gizmo( ); } } + +// fn auto_remove_pickable( +// mut commands : Commands, +// grids : Query, Or<(With, With)>)> +// ) { +// for e in grids.iter() { +// commands.entity(e).remove::(); +// } +// } \ No newline at end of file diff --git a/src/editor/ui/hierarchy.rs b/src/editor/ui/hierarchy.rs index a8be93f2..1446b1f9 100644 --- a/src/editor/ui/hierarchy.rs +++ b/src/editor/ui/hierarchy.rs @@ -180,7 +180,7 @@ fn clone_enitites( mut events: EventReader, editor_registry: Res, ) { - for event in events.into_iter() { + for event in events.read() { let mut queue = vec![(event.id, commands.spawn_empty().id())]; let mut map = HashMap::new(); diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index 1d9838f1..c820df9c 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -201,18 +201,30 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { { let (ptr, mut set_changed) = mut_untyped_split(data); - let value = reflect_from_ptr.as_reflect_ptr_mut(ptr); + let value = reflect_from_ptr.from_ptr_mut()(ptr); + + let name = { + if let Some(c_id) = cell.components().get_resource_id(registration.type_id()) { + let info = cell.components().get_info(c_id).unwrap(); + pretty_type_name::pretty_type_name_str(info.name()) + } else { + "Unknown".to_string() + } + }; + + pretty_type_name::pretty_type_name_str(registration.type_info().type_path()); + if !editor_registry.silent.contains(®istration.type_id()) { ui.push_id( - format!("{:?}-{}", &e.id(), ®istration.short_name()), + format!("{:?}-{}", &e.id(), &name), |ui| { - ui.collapsing(registration.short_name(), |ui| { + ui.collapsing(&name, |ui| { ui.push_id( format!( "content-{:?}-{}", &e.id(), - ®istration.short_name() + &name ), |ui| { if env.ui_for_reflect_with_options( @@ -233,7 +245,7 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { format!( "del component {:?}-{}", &e.id(), - ®istration.short_name() + &name ), |ui| { //must be on top @@ -272,7 +284,9 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { for idx in 0..components_id.len() { let c_id = components_id[idx]; let t_id = types_id[idx]; - let name = registry.get(t_id).unwrap().short_name(); + let name = pretty_type_name::pretty_type_name_str( + cell.components().get_info(c_id).unwrap().name(), + ); if name.to_lowercase().contains(&lower_filter) { ui.label(name); diff --git a/src/editor/ui/mod.rs b/src/editor/ui/mod.rs index e3cf9eef..87913510 100644 --- a/src/editor/ui/mod.rs +++ b/src/editor/ui/mod.rs @@ -251,7 +251,7 @@ impl EditorUiAppExt for App { tab_systesm: impl IntoSystemConfigs, ) -> &mut Self { let mut tab = ScheduleEditorTab { - schedule: Schedule::new(), + schedule: Schedule::default(), title, }; diff --git a/src/editor_registry/mod.rs b/src/editor_registry/mod.rs index b68880e3..e1f04aaa 100644 --- a/src/editor_registry/mod.rs +++ b/src/editor_registry/mod.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use bevy::{ ecs::system::{EntityCommand, EntityCommands}, prelude::*, - reflect::{GetTypeRegistration, TypePath, TypeRegistry}, + reflect::{GetTypeRegistration, TypePath, TypeRegistry, TypeRegistryArc}, utils::{HashMap, HashSet}, }; @@ -84,7 +84,7 @@ impl AddDefaultComponent { /// Resource, which contains all custom editor registry #[derive(Default, Resource, Clone)] pub struct EditorRegistry { - pub registry: TypeRegistry, + pub registry: TypeRegistryArc, pub spawn_components: HashMap, pub clone_components: Vec, pub remove_components: HashMap, diff --git a/src/lib.rs b/src/lib.rs index e2edb449..6d450742 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ use prefab::PrefabPlugin; pub mod ext { pub use bevy::prelude::*; pub use bevy_egui::*; - pub use bevy_infinite_grid::*; + pub use bevy_debug_grid::*; pub use bevy_inspector_egui::prelude::*; pub use bevy_mod_picking::prelude::*; pub use bevy_panorbit_camera::*; @@ -124,15 +124,6 @@ pub fn simple_editor_setup(mut commands: Commands) { ..default() }); - //grid - commands.spawn(bevy_infinite_grid::InfiniteGridBundle { - grid: bevy_infinite_grid::InfiniteGrid { - // shadow_color: None, - ..default() - }, - ..default() - }); - // camera commands .spawn(Camera3dBundle { @@ -140,6 +131,8 @@ pub fn simple_editor_setup(mut commands: Commands) { ..default() }) .insert(bevy_panorbit_camera::PanOrbitCamera::default()) - .insert(bevy_mod_picking::prelude::RaycastPickCamera::default()) .insert(EditorCameraMarker); + + + bevy_debug_grid::spawn_floor_grid(commands); } diff --git a/src/optional/bevy_xpbd_plugin/collider.rs b/src/optional/bevy_xpbd_plugin/collider.rs index 8828958d..0ca322cb 100644 --- a/src/optional/bevy_xpbd_plugin/collider.rs +++ b/src/optional/bevy_xpbd_plugin/collider.rs @@ -141,13 +141,7 @@ pub fn update_collider( for (e, collider, mesh) in updated_meshes.iter() { if *collider == ColliderPrefab::FromMesh { if let Some(mesh) = meshes.get(mesh) { - if let Some(col) = Collider::convex_decomposition_from_bevy_mesh(mesh) { - commands.entity(e).insert(col); - } else { - commands - .entity(e) - .insert(Collider::trimesh_from_bevy_mesh(mesh).unwrap_or_default()); - } + commands.entity(e).insert(Collider::trimesh_from_mesh(mesh).unwrap_or_default()); } else { commands.entity(e).insert(Collider::default()); } @@ -172,7 +166,7 @@ fn get_collider( ColliderPrefab::FromMesh => { if let Some(mesh) = mesh { if let Some(mesh) = meshes.get(mesh) { - Collider::trimesh_from_bevy_mesh(mesh).unwrap_or_default() + Collider::trimesh_from_mesh(mesh).unwrap_or_default() } else { Collider::default() } @@ -233,20 +227,20 @@ fn get_prefab_mesh_collider(mesh: &MeshPrimitivePrefab) -> Collider { } MeshPrimitivePrefab::Capsule(val) => Collider::capsule(1.0, val.r as Scalar), MeshPrimitivePrefab::Circle(val) => { - Collider::trimesh_from_bevy_mesh(&val.to_mesh()).unwrap_or_default() + Collider::trimesh_from_mesh(&val.to_mesh()).unwrap_or_default() } MeshPrimitivePrefab::Cylinder(val) => Collider::cylinder(1.0, val.r as Scalar), MeshPrimitivePrefab::Icosphere(val) => { - Collider::trimesh_from_bevy_mesh(&val.to_mesh()).unwrap_or_default() + Collider::trimesh_from_mesh(&val.to_mesh()).unwrap_or_default() } MeshPrimitivePrefab::Plane(val) => { Collider::cuboid(val.size as Scalar, EPS as Scalar, val.size as Scalar) } MeshPrimitivePrefab::RegularPolygon(val) => { - Collider::trimesh_from_bevy_mesh(&val.to_mesh()).unwrap_or_default() + Collider::trimesh_from_mesh(&val.to_mesh()).unwrap_or_default() } MeshPrimitivePrefab::Torus(val) => { - Collider::trimesh_from_bevy_mesh(&val.to_mesh()).unwrap_or_default() + Collider::trimesh_from_mesh(&val.to_mesh()).unwrap_or_default() } } } diff --git a/src/prefab/component/mod.rs b/src/prefab/component/mod.rs index 6de0d8c4..be37b024 100644 --- a/src/prefab/component/mod.rs +++ b/src/prefab/component/mod.rs @@ -62,7 +62,7 @@ impl AutoStruct { let field_name = s.name_at(idx).unwrap(); let field = s.field_at(idx).unwrap(); if let Some(handle) = field.downcast_ref::>() { - if let Some(path) = assets.get_handle_path(handle) { + if let Some(path) = handle.path() { let path = path.path().to_str().unwrap().to_string(); paths.insert(field_name.to_string(), path); } diff --git a/src/prefab/load.rs b/src/prefab/load.rs index efb83547..dc8506eb 100644 --- a/src/prefab/load.rs +++ b/src/prefab/load.rs @@ -12,7 +12,8 @@ pub struct PrefabBundle { global_transform: GlobalTransform, visiblity: Visibility, - computed_visiblity: ComputedVisibility, + computed_visiblity: ViewVisibility, + inherited_visibility: InheritedVisibility, } impl PrefabBundle { diff --git a/src/prefab/mod.rs b/src/prefab/mod.rs index 161d4f6f..4adab550 100644 --- a/src/prefab/mod.rs +++ b/src/prefab/mod.rs @@ -129,7 +129,9 @@ impl Plugin for BasePrefabPlugin { app.editor_relation::(); app.editor_relation::(); app.editor_relation::(); - app.editor_relation::(); + app.editor_relation::(); + app.editor_relation::(); + app.editor_relation::(); @@ -227,19 +229,19 @@ fn remove_global_transform( fn add_computed_visibility( mut commands: Commands, - query: Query, Without)>, + query: Query, Without)>, ) { for e in query.iter() { - commands.entity(e).insert(ComputedVisibility::default()); + commands.entity(e).insert(ViewVisibility::default()).insert(InheritedVisibility::default()); } } fn remove_computed_visibility( mut commands: Commands, - query: Query, With)>, + query: Query, With)>, ) { for e in query.iter() { - commands.entity(e).remove::(); + commands.entity(e).remove::().remove::(); } } @@ -252,10 +254,10 @@ fn sync_asset_mesh( for (e, mesh) in changed.iter() { commands .entity(e) - .insert(assets.load::(&mesh.path)); + .insert(assets.load::(&mesh.path)); } - for e in deleted.iter() { + for e in deleted.read() { if let Some(mut cmd) = commands.get_entity(e) { cmd.remove::>(); info!("Removed mesh handle for {:?}", e); @@ -272,7 +274,7 @@ fn sync_asset_material( for (e, material) in changed.iter() { commands .entity(e) - .insert(assets.load::(&material.path)); + .insert(assets.load::(&material.path)); } for e in deleted.iter() { diff --git a/src/prefab/save.rs b/src/prefab/save.rs index 7bb052c6..9a670228 100644 --- a/src/prefab/save.rs +++ b/src/prefab/save.rs @@ -96,7 +96,7 @@ pub fn serialize_prefab(world: &mut World) { .map(|a| a.type_id()) .collect(); let mut builder = DynamicSceneBuilder::from_world(world); - builder + builder = builder .allow_all() .with_filter(SceneFilter::Allowlist(HashSet::from_iter( allow_types.iter().cloned(), From 0e00eec559466bc3b99377739b29d344d37084c1 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 20:04:06 +0300 Subject: [PATCH 02/35] FIxed omponents name and visible defaults --- src/editor/ui/inspector/mod.rs | 12 +++--------- src/prefab/mod.rs | 4 +++- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index c820df9c..92674db8 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -181,7 +181,7 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { let e_id = e.id().index(); egui::Grid::new(format!("{e_id}")).show(ui, |ui| { for idx in 0..components_id.len() { - let c_id = components_by_entity + let c_id: ComponentId = components_by_entity .entry(e_id) .or_insert(Vec::new()) .get(idx) @@ -204,16 +204,10 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { let value = reflect_from_ptr.from_ptr_mut()(ptr); let name = { - if let Some(c_id) = cell.components().get_resource_id(registration.type_id()) { - let info = cell.components().get_info(c_id).unwrap(); - pretty_type_name::pretty_type_name_str(info.name()) - } else { - "Unknown".to_string() - } + let info = cell.components().get_info(c_id).unwrap(); + pretty_type_name::pretty_type_name_str(info.name()) }; - pretty_type_name::pretty_type_name_str(registration.type_info().type_path()); - if !editor_registry.silent.contains(®istration.type_id()) { ui.push_id( diff --git a/src/prefab/mod.rs b/src/prefab/mod.rs index 4adab550..162cc54a 100644 --- a/src/prefab/mod.rs +++ b/src/prefab/mod.rs @@ -232,7 +232,9 @@ fn add_computed_visibility( query: Query, Without)>, ) { for e in query.iter() { - commands.entity(e).insert(ViewVisibility::default()).insert(InheritedVisibility::default()); + commands.entity(e) + .insert(ViewVisibility::default()) + .insert(InheritedVisibility::VISIBLE); } } From e58fef0dd65facc666f32ca552fdbef53c9ab515 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 22:19:15 +0300 Subject: [PATCH 03/35] Fix picking, fix platformer scene --- Cargo.toml | 2 +- assets/level_test.scn.ron | 32 ++++++++++++++++---------------- src/editor/mod.rs | 14 +++++++------- src/lib.rs | 5 ++++- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a597bbb7..dc28da8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ ron = "0.8" bevy_panorbit_camera = {version = "0.9", features=["bevy_egui"]} bevy-inspector-egui = {version = "0.21", features = ["bevy_pbr", "highlight_changes"]} pretty-type-name = "1.0" -bevy_mod_picking = {version = "0.17", features = ["backend_egui"]} +bevy_mod_picking = {version = "0.17", default-features = false, features = ["backend_raycast", "selection"]} bevy_debug_grid = "0.3" egui_dock = "0.8" egui_file = "0.11" diff --git a/assets/level_test.scn.ron b/assets/level_test.scn.ron index c45bd8a4..3a0bab3c 100644 --- a/assets/level_test.scn.ron +++ b/assets/level_test.scn.ron @@ -9,7 +9,7 @@ y: 1.5396833, z: -25.659279, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -102,7 +102,7 @@ y: 0.0, z: -16.504646, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -195,7 +195,7 @@ y: 0.0, z: -6.3498917, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -288,7 +288,7 @@ y: 0.21842504, z: -0.4569779, ), - rotation: (0.0, -0.00000000046566123, 0.0, 1.0), + rotation: (x: 0.0, y: -0.00000000046566123, z: 0.0, w: 1.0), scale: ( x: 1.0000001, y: 1.0, @@ -343,7 +343,7 @@ y: 0.0, z: -25.785236, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -436,7 +436,7 @@ y: -0.28648877, z: -0.28093243, ), - rotation: (-0.6675922, 0.0, 0.0, 0.7445271), + rotation: (x: -0.6675922, y: 0.0, z: 0.0, w: 0.7445271), scale: ( x: 1.0, y: 1.0, @@ -511,7 +511,7 @@ y: -0.07585633, z: -0.5607872, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -566,7 +566,7 @@ y: -1.2103212, z: -25.835867, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -659,7 +659,7 @@ y: 1.4635863, z: -30.082056, ), - rotation: (-0.7019975, 0.0, 0.0, 0.7121794), + rotation: (x: -0.7019975, y: 0.0, z: 0.0, w: 0.7121794), scale: ( x: 1.0, y: 0.99999726, @@ -734,7 +734,7 @@ y: 1.5396833, z: -43.377647, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -827,7 +827,7 @@ y: -0.000009655952, z: 7.3677998, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -920,7 +920,7 @@ y: 1.5396833, z: -38.380207, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -1013,7 +1013,7 @@ y: 0.21842492, z: -0.45153165, ), - rotation: (0.0, -0.00000000046566123, 0.0, 1.0), + rotation: (x: 0.0, y: -0.00000000046566123, z: 0.0, w: 1.0), scale: ( x: 1.0000001, y: 0.99999964, @@ -1068,7 +1068,7 @@ y: 0.0, z: 2.2603722, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -1161,7 +1161,7 @@ y: 2.7637057, z: 6.4066534, ), - rotation: (-0.00000000033425, 0.71091986, -0.00000000033425004, -0.7032731), + rotation: (x: -0.00000000033425, y: 0.71091986, z: -0.00000000033425004, w: -0.7032731), scale: ( x: 1.0000397, y: 0.9999999, @@ -1272,7 +1272,7 @@ y: 3.735711, z: 0.0, ), - rotation: (-0.1146213, 0.6778526, 0.12107966, 0.716043), + rotation: (x: -0.1146213, y: 0.6778526, z: 0.12107966, w: 0.716043), scale: ( x: 0.9999996, y: 0.9999984, diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 6732e81f..3b1299f7 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -9,7 +9,7 @@ pub mod ui_registration; use bevy_egui::{EguiContext, EguiContexts}; use bevy_inspector_egui::{quick::WorldInspectorPlugin, DefaultInspectorConfigPlugin}; -use bevy_mod_picking::{prelude::*, PickableBundle, backends::raycast::bevy_mod_raycast::prelude::RaycastSettings}; +use bevy_mod_picking::{prelude::*, PickableBundle, backends::raycast::{bevy_mod_raycast::prelude::RaycastSettings, RaycastPickable}}; use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraSystemSet}; use crate::{ @@ -48,9 +48,6 @@ impl Plugin for EditorPlugin { if !app.is_plugin_added::() { app.add_plugins( bevy_mod_picking::DefaultPickingPlugins - .build() - .disable::() - .disable::(), ); app.world.resource_mut::().require_markers = true; @@ -162,7 +159,8 @@ fn auto_add_picking( commands .entity(e) .insert(PickableBundle::default()) - .insert(On::>::send_event::()); + .insert(On::>::send_event::()) + .insert(RaycastPickable); } } @@ -183,7 +181,8 @@ fn auto_add_picking_dummy( if mesh.primitive_topology() == PrimitiveTopology::TriangleList { commands .entity(e) - .insert(PickableBundle::default()); + .insert(PickableBundle::default()) + .insert(RaycastPickable); } } } @@ -200,7 +199,8 @@ fn select_listener( if !pan_orbit_state.0 { return; } - for event in events.iter() { + for event in events.read() { + info!("Select Event: {:?}", event.e); match event.event.button { PointerButton::Primary => { commands.entity(event.e).insert(core::Selected); diff --git a/src/lib.rs b/src/lib.rs index 6d450742..b41562db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ pub mod optional; use bevy::{pbr::CascadeShadowConfigBuilder, prelude::*}; +use bevy_mod_picking::{backends::raycast::RaycastPickable, PickableBundle}; use editor::EditorPlugin; use optional::OptionalPlugin; use prefab::PrefabPlugin; @@ -131,7 +132,9 @@ pub fn simple_editor_setup(mut commands: Commands) { ..default() }) .insert(bevy_panorbit_camera::PanOrbitCamera::default()) - .insert(EditorCameraMarker); + .insert(EditorCameraMarker) + .insert(PickableBundle::default()) + .insert(RaycastPickable); bevy_debug_grid::spawn_floor_grid(commands); From 12b10984e050e580e6ef0295a250e1cbeddbd05a Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 22:28:15 +0300 Subject: [PATCH 04/35] Fix platformer example --- examples/platformer.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/platformer.rs b/examples/platformer.rs index 8142c26e..8a286dd8 100644 --- a/examples/platformer.rs +++ b/examples/platformer.rs @@ -29,10 +29,9 @@ fn main() { simple_tab_system, ) .add_systems( - PhysicsSchedule, + Update, move_player - .run_if(in_state(EditorState::Game)) - .before(PhysicsStepSet::BroadPhase), + .run_if(in_state(EditorState::Game)), ) .add_systems(Update, camera_follow.run_if(in_state(EditorState::Game))) .run(); @@ -105,7 +104,7 @@ fn move_player( ) { for (_e, mut vel, mut rot, mut controller, hits, tranform) in query.iter_mut() { //take 1th hit, because 0th hit is self hit - if let Some(hit) = hits.iter_sorted().nth(1) { + if let Some(hit) = hits.iter_sorted().nth(0) { if hit.time_of_impact > 0.7 { continue; } From 499394909d8932072707b89dd7cecb3893f48772 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 22:32:45 +0300 Subject: [PATCH 05/35] Fix physics spawn and simple spawn examples --- assets/physics_loading_test.scn.ron | 10 +++++----- assets/tile.scn.ron | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/assets/physics_loading_test.scn.ron b/assets/physics_loading_test.scn.ron index d125d78d..4c4946f2 100644 --- a/assets/physics_loading_test.scn.ron +++ b/assets/physics_loading_test.scn.ron @@ -9,7 +9,7 @@ y: 11.90253, z: 0.574896, ), - rotation: (-0.0000000005767191, 0.7109159, -0.0000000005767191, -0.70327705), + rotation: (x: -0.0000000005767191, y: 0.7109159, z: -0.0000000005767191, w: -0.70327705), scale: ( x: 1.0000631, y: 1.0000006, @@ -103,7 +103,7 @@ y: 0.21842492, z: -0.45153165, ), - rotation: (0.0, -0.00000000046566123, 0.0, 1.0), + rotation: (x: 0.0, y: -0.00000000046566123, z: 0.0, w: 1.0), scale: ( x: 1.0000001, y: 0.99999964, @@ -158,7 +158,7 @@ y: -0.000009655952, z: 0.38997746, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 1.0, y: 1.0, @@ -251,7 +251,7 @@ y: 0.0, z: -0.4533022, ), - rotation: (0.000000000000018831962, -0.00000000046566245, 0.0000000000019876305, 1.0), + rotation: (x: 0.000000000000018831962, y: -0.00000000046566245, z: 0.0000000000019876305, w: 1.0), scale: ( x: 0.99999756, y: 0.9999971, @@ -306,7 +306,7 @@ y: 0.21842504, z: -0.4569779, ), - rotation: (0.0, -0.00000000046566123, 0.0, 1.0), + rotation: (x: 0.0, y: -0.00000000046566123, z: 0.0, w: 1.0), scale: ( x: 1.0000001, y: 1.0, diff --git a/assets/tile.scn.ron b/assets/tile.scn.ron index 15516b5a..e1757a5f 100644 --- a/assets/tile.scn.ron +++ b/assets/tile.scn.ron @@ -9,7 +9,7 @@ y: 0.0, z: 0.0, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 2.4347973, y: 0.15754807, @@ -34,7 +34,7 @@ y: 0.13795531, z: -2.1002147, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 0.4790529, y: 0.36931515, @@ -60,7 +60,7 @@ y: 0.13795531, z: -2.0787163, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 0.4790529, y: 0.36931515, @@ -87,7 +87,7 @@ y: 0.13796866, z: 2.0884218, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 0.4790529, y: 0.36931515, @@ -114,7 +114,7 @@ y: 0.13795578, z: 2.0741177, ), - rotation: (0.0, 0.0, 0.0, 1.0), + rotation: (x: 0.0, y: 0.0, z: 0.0, w: 1.0), scale: ( x: 0.4790529, y: 0.36931515, From 081aa3f0a74d0e6626ee5ef9e4c65729f8c39f65 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 22:35:04 +0300 Subject: [PATCH 06/35] cargo fmt --- examples/platformer.rs | 6 +-- src/editor/core/gltf_unpack.rs | 2 +- src/editor/mod.rs | 43 ++++++++++---------- src/editor/ui/inspector/mod.rs | 48 +++++++++-------------- src/lib.rs | 3 +- src/optional/bevy_xpbd_plugin/collider.rs | 4 +- src/prefab/mod.rs | 17 ++++---- 7 files changed, 55 insertions(+), 68 deletions(-) diff --git a/examples/platformer.rs b/examples/platformer.rs index 8a286dd8..f4a36bd1 100644 --- a/examples/platformer.rs +++ b/examples/platformer.rs @@ -28,11 +28,7 @@ fn main() { "Simnple tab".into(), simple_tab_system, ) - .add_systems( - Update, - move_player - .run_if(in_state(EditorState::Game)), - ) + .add_systems(Update, move_player.run_if(in_state(EditorState::Game))) .add_systems(Update, camera_follow.run_if(in_state(EditorState::Game))) .run(); } diff --git a/src/editor/core/gltf_unpack.rs b/src/editor/core/gltf_unpack.rs index f1c7b7a0..1655f2ef 100644 --- a/src/editor/core/gltf_unpack.rs +++ b/src/editor/core/gltf_unpack.rs @@ -84,7 +84,7 @@ fn unpack_gltf(world: &mut World) { let mut command_queue = CommandQueue::default(); for gltf in loaded_scenes.iter() { let handle: Handle = gltf.0.clone(); - let gltf_path= if let Some(path) = handle.path() { + let gltf_path = if let Some(path) = handle.path() { path.clone() } else { continue; diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 3b1299f7..6044135d 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -1,6 +1,6 @@ //code only for editor gui -use bevy::{prelude::*, window::PrimaryWindow, render::render_resource::PrimitiveTopology}; +use bevy::{prelude::*, render::render_resource::PrimitiveTopology, window::PrimaryWindow}; pub mod core; pub mod ui; @@ -9,7 +9,11 @@ pub mod ui_registration; use bevy_egui::{EguiContext, EguiContexts}; use bevy_inspector_egui::{quick::WorldInspectorPlugin, DefaultInspectorConfigPlugin}; -use bevy_mod_picking::{prelude::*, PickableBundle, backends::raycast::{bevy_mod_raycast::prelude::RaycastSettings, RaycastPickable}}; +use bevy_mod_picking::{ + backends::raycast::{bevy_mod_raycast::prelude::RaycastSettings, RaycastPickable}, + prelude::*, + PickableBundle, +}; use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraSystemSet}; use crate::{ @@ -46,11 +50,11 @@ impl Plugin for EditorPlugin { .add_plugins(PanOrbitCameraPlugin); if !app.is_plugin_added::() { - app.add_plugins( - bevy_mod_picking::DefaultPickingPlugins - ); + app.add_plugins(bevy_mod_picking::DefaultPickingPlugins); - app.world.resource_mut::().require_markers = true; + app.world + .resource_mut::() + .require_markers = true; } if !app.is_plugin_added::() { @@ -108,15 +112,10 @@ impl Plugin for EditorPlugin { app.add_systems( PostUpdate, - ( - auto_add_picking, - select_listener.after(UiSystemSet), - ) + (auto_add_picking, select_listener.after(UiSystemSet)) .run_if(in_state(EditorState::Editor)), ); - app.add_systems( - PostUpdate, - auto_add_picking_dummy); + app.add_systems(PostUpdate, auto_add_picking_dummy); app.add_systems( Update, @@ -165,16 +164,18 @@ fn auto_add_picking( } type AutoAddQueryFilter = ( - Without, - Without, - With, - Changed>); + Without, + Without, + With, + Changed>, +); //Auto add picking for each child to propagate picking event up to prefab entitiy fn auto_add_picking_dummy( - mut commands: Commands, - query : Query<(Entity, &Handle), AutoAddQueryFilter>, - meshs : Res>) { + mut commands: Commands, + query: Query<(Entity, &Handle), AutoAddQueryFilter>, + meshs: Res>, +) { for (e, mesh) in query.iter() { //Only meshed entity need to be pickable if let Some(mesh) = meshs.get(mesh) { @@ -392,4 +393,4 @@ fn draw_camera_gizmo( // for e in grids.iter() { // commands.entity(e).remove::(); // } -// } \ No newline at end of file +// } diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index 92674db8..c141de07 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -208,39 +208,27 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { pretty_type_name::pretty_type_name_str(info.name()) }; - if !editor_registry.silent.contains(®istration.type_id()) { - ui.push_id( - format!("{:?}-{}", &e.id(), &name), - |ui| { - ui.collapsing(&name, |ui| { - ui.push_id( - format!( - "content-{:?}-{}", - &e.id(), - &name - ), - |ui| { - if env.ui_for_reflect_with_options( - value, - ui, - ui.id(), - &(), - ) { - set_changed(); - } - }, - ); - }); - }, - ); + ui.push_id(format!("{:?}-{}", &e.id(), &name), |ui| { + ui.collapsing(&name, |ui| { + ui.push_id( + format!("content-{:?}-{}", &e.id(), &name), + |ui| { + if env.ui_for_reflect_with_options( + value, + ui, + ui.id(), + &(), + ) { + set_changed(); + } + }, + ); + }); + }); ui.push_id( - format!( - "del component {:?}-{}", - &e.id(), - &name - ), + format!("del component {:?}-{}", &e.id(), &name), |ui| { //must be on top ui.with_layout( diff --git a/src/lib.rs b/src/lib.rs index b41562db..9f2d0ddf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,8 +26,8 @@ use prefab::PrefabPlugin; /// Public usage of packages that used in this crate pub mod ext { pub use bevy::prelude::*; - pub use bevy_egui::*; pub use bevy_debug_grid::*; + pub use bevy_egui::*; pub use bevy_inspector_egui::prelude::*; pub use bevy_mod_picking::prelude::*; pub use bevy_panorbit_camera::*; @@ -136,6 +136,5 @@ pub fn simple_editor_setup(mut commands: Commands) { .insert(PickableBundle::default()) .insert(RaycastPickable); - bevy_debug_grid::spawn_floor_grid(commands); } diff --git a/src/optional/bevy_xpbd_plugin/collider.rs b/src/optional/bevy_xpbd_plugin/collider.rs index 0ca322cb..5a7fd4d4 100644 --- a/src/optional/bevy_xpbd_plugin/collider.rs +++ b/src/optional/bevy_xpbd_plugin/collider.rs @@ -141,7 +141,9 @@ pub fn update_collider( for (e, collider, mesh) in updated_meshes.iter() { if *collider == ColliderPrefab::FromMesh { if let Some(mesh) = meshes.get(mesh) { - commands.entity(e).insert(Collider::trimesh_from_mesh(mesh).unwrap_or_default()); + commands + .entity(e) + .insert(Collider::trimesh_from_mesh(mesh).unwrap_or_default()); } else { commands.entity(e).insert(Collider::default()); } diff --git a/src/prefab/mod.rs b/src/prefab/mod.rs index 162cc54a..11a65abf 100644 --- a/src/prefab/mod.rs +++ b/src/prefab/mod.rs @@ -132,7 +132,6 @@ impl Plugin for BasePrefabPlugin { app.editor_relation::(); app.editor_relation::(); - app.editor_relation::(); //Light @@ -232,9 +231,10 @@ fn add_computed_visibility( query: Query, Without)>, ) { for e in query.iter() { - commands.entity(e) - .insert(ViewVisibility::default()) - .insert(InheritedVisibility::VISIBLE); + commands + .entity(e) + .insert(ViewVisibility::default()) + .insert(InheritedVisibility::VISIBLE); } } @@ -243,7 +243,10 @@ fn remove_computed_visibility( query: Query, With)>, ) { for e in query.iter() { - commands.entity(e).remove::().remove::(); + commands + .entity(e) + .remove::() + .remove::(); } } @@ -254,9 +257,7 @@ fn sync_asset_mesh( assets: Res, ) { for (e, mesh) in changed.iter() { - commands - .entity(e) - .insert(assets.load::(&mesh.path)); + commands.entity(e).insert(assets.load::(&mesh.path)); } for e in deleted.read() { From 475c88995fc5063bba9603049bbd3d5165283ebf Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 22:38:41 +0300 Subject: [PATCH 07/35] cargo clippy --- examples/platformer.rs | 3 +-- src/editor/core/gltf_unpack.rs | 4 ++-- src/editor/core/mod.rs | 2 +- src/editor/mod.rs | 4 ++-- src/editor/ui/bot_menu.rs | 2 +- src/editor/ui/inspector/mod.rs | 2 +- src/editor/ui/mod.rs | 2 +- src/editor_registry/mod.rs | 2 +- src/lib.rs | 2 +- src/prefab/component/mod.rs | 2 +- src/prefab/mod.rs | 6 +++--- src/prefab/spawn_system.rs | 2 +- 12 files changed, 16 insertions(+), 17 deletions(-) diff --git a/examples/platformer.rs b/examples/platformer.rs index f4a36bd1..5f48a07a 100644 --- a/examples/platformer.rs +++ b/examples/platformer.rs @@ -8,7 +8,6 @@ use bevy::{ }; use bevy_xpbd_3d::{ prelude::{AngularVelocity, LinearVelocity, Position, RayHits}, - PhysicsSchedule, PhysicsStepSet, }; use space_editor::prelude::{component::EntityLink, spatial_query::RayCasterPrefab, *}; @@ -100,7 +99,7 @@ fn move_player( ) { for (_e, mut vel, mut rot, mut controller, hits, tranform) in query.iter_mut() { //take 1th hit, because 0th hit is self hit - if let Some(hit) = hits.iter_sorted().nth(0) { + if let Some(hit) = hits.iter_sorted().next() { if hit.time_of_impact > 0.7 { continue; } diff --git a/src/editor/core/gltf_unpack.rs b/src/editor/core/gltf_unpack.rs index 1655f2ef..560db208 100644 --- a/src/editor/core/gltf_unpack.rs +++ b/src/editor/core/gltf_unpack.rs @@ -48,7 +48,7 @@ fn unpack_gltf_event( assets: Res, mut queue: ResMut, ) { - for event in events.iter() { + for event in events.read() { queue.0.push(assets.load(event.path.clone())); } events.clear(); @@ -76,7 +76,7 @@ fn unpack_gltf(world: &mut World) { let loaded_scenes = { let mut events = world.resource_mut::>(); let mut reader = events.get_reader(); - let loaded = reader.iter(&events).cloned().collect::>(); + let loaded = reader.read(&events).cloned().collect::>(); events.clear(); loaded }; diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index 19fd7390..700475c1 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -70,7 +70,7 @@ fn editor_event_listener( cache: ResMut, mut gltf_events: EventWriter, ) { - for event in events.iter() { + for event in events.read() { match event { EditorEvent::Load(path) => match path { EditorPrefabPath::File(path) => { diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 6044135d..f023f32e 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -10,7 +10,7 @@ pub mod ui_registration; use bevy_egui::{EguiContext, EguiContexts}; use bevy_inspector_egui::{quick::WorldInspectorPlugin, DefaultInspectorConfigPlugin}; use bevy_mod_picking::{ - backends::raycast::{bevy_mod_raycast::prelude::RaycastSettings, RaycastPickable}, + backends::raycast::{RaycastPickable}, prelude::*, PickableBundle, }; @@ -140,7 +140,7 @@ struct SelectEvent { event: ListenerInput>, } -fn create_grid_lines(mut commands: Commands) { +fn create_grid_lines(commands: Commands) { bevy_debug_grid::spawn_floor_grid(commands); } diff --git a/src/editor/ui/bot_menu.rs b/src/editor/ui/bot_menu.rs index 21caed36..b5eabdae 100644 --- a/src/editor/ui/bot_menu.rs +++ b/src/editor/ui/bot_menu.rs @@ -184,7 +184,7 @@ pub fn bot_menu( }); }); - for event in events.iter() { + for event in events.read() { menu_state.path = event.path.clone(); editor_events.send(EditorEvent::Load(EditorPrefabPath::File(format!( "{}.scn.ron", diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index c141de07..02a0d5ae 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -265,7 +265,7 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { let _counter = 0; for idx in 0..components_id.len() { let c_id = components_id[idx]; - let t_id = types_id[idx]; + let _t_id = types_id[idx]; let name = pretty_type_name::pretty_type_name_str( cell.components().get_info(c_id).unwrap().name(), ); diff --git a/src/editor/ui/mod.rs b/src/editor/ui/mod.rs index 87913510..878e7bcb 100644 --- a/src/editor/ui/mod.rs +++ b/src/editor/ui/mod.rs @@ -62,7 +62,7 @@ impl Plugin for EditorUiPlugin { app.add_plugins(bot_menu::BotMenuPlugin); - app.configure_set( + app.configure_sets( Update, UiSystemSet .in_set(EditorSet::Editor) diff --git a/src/editor_registry/mod.rs b/src/editor_registry/mod.rs index e1f04aaa..e5887003 100644 --- a/src/editor_registry/mod.rs +++ b/src/editor_registry/mod.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use bevy::{ ecs::system::{EntityCommand, EntityCommands}, prelude::*, - reflect::{GetTypeRegistration, TypePath, TypeRegistry, TypeRegistryArc}, + reflect::{GetTypeRegistration, TypePath, TypeRegistryArc}, utils::{HashMap, HashSet}, }; diff --git a/src/lib.rs b/src/lib.rs index 9f2d0ddf..80e1c6e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ use prefab::PrefabPlugin; /// Public usage of packages that used in this crate pub mod ext { pub use bevy::prelude::*; - pub use bevy_debug_grid::*; + pub use bevy_debug_grid; pub use bevy_egui::*; pub use bevy_inspector_egui::prelude::*; pub use bevy_mod_picking::prelude::*; diff --git a/src/prefab/component/mod.rs b/src/prefab/component/mod.rs index be37b024..2814e32b 100644 --- a/src/prefab/component/mod.rs +++ b/src/prefab/component/mod.rs @@ -54,7 +54,7 @@ pub struct AutoStruct { } impl AutoStruct { - pub fn new(data: &T, assets: &AssetServer) -> AutoStruct { + pub fn new(data: &T, _assets: &AssetServer) -> AutoStruct { let mut paths = HashMap::new(); if let ReflectRef::Struct(s) = data.reflect_ref() { diff --git a/src/prefab/mod.rs b/src/prefab/mod.rs index 11a65abf..774531f8 100644 --- a/src/prefab/mod.rs +++ b/src/prefab/mod.rs @@ -58,8 +58,8 @@ impl Plugin for BasePrefabPlugin { app.add_plugins(EditorRegistryPlugin); } - app.configure_set(Update, EditorSet::Game.run_if(in_state(EditorState::Game))); - app.configure_set( + app.configure_sets(Update, EditorSet::Game.run_if(in_state(EditorState::Game))); + app.configure_sets( Update, EditorSet::Editor.run_if(in_state(EditorState::Editor)), ); @@ -280,7 +280,7 @@ fn sync_asset_material( .insert(assets.load::(&material.path)); } - for e in deleted.iter() { + for e in deleted.read() { if let Some(mut cmd) = commands.get_entity(e) { cmd.remove::>(); } diff --git a/src/prefab/spawn_system.rs b/src/prefab/spawn_system.rs index bd8702e5..7d9e4915 100644 --- a/src/prefab/spawn_system.rs +++ b/src/prefab/spawn_system.rs @@ -88,7 +88,7 @@ pub fn editor_remove_mesh( mut commands: Commands, mut query: RemovedComponents, ) { - for e in query.iter() { + for e in query.read() { if let Some(mut cmd) = commands.get_entity(e) { cmd.remove::>(); info!("Removed mesh handle for {:?}", e); From 033c747afa28a6cf54f75c88245dc509937d1c9d Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 22:43:11 +0300 Subject: [PATCH 08/35] Update Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dc28da8d..a0f545bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ bevy_egui = "0.23" egui-gizmo = "0.12" bevy-scene-hook = "9" ron = "0.8" -bevy_panorbit_camera = {version = "0.9", features=["bevy_egui"]} +bevy_panorbit_camera = "0.9" bevy-inspector-egui = {version = "0.21", features = ["bevy_pbr", "highlight_changes"]} pretty-type-name = "1.0" bevy_mod_picking = {version = "0.17", default-features = false, features = ["backend_raycast", "selection"]} From 0d99388e8c593c0519eac45c8fa1618f576db16d Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 22:47:10 +0300 Subject: [PATCH 09/35] cargo fmt again --- examples/platformer.rs | 4 +--- src/editor/mod.rs | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/examples/platformer.rs b/examples/platformer.rs index 5f48a07a..d6f58108 100644 --- a/examples/platformer.rs +++ b/examples/platformer.rs @@ -6,9 +6,7 @@ use bevy::{ ecs::{entity::MapEntities, reflect::ReflectMapEntities}, prelude::*, }; -use bevy_xpbd_3d::{ - prelude::{AngularVelocity, LinearVelocity, Position, RayHits}, -}; +use bevy_xpbd_3d::prelude::{AngularVelocity, LinearVelocity, Position, RayHits}; use space_editor::prelude::{component::EntityLink, spatial_query::RayCasterPrefab, *}; fn main() { diff --git a/src/editor/mod.rs b/src/editor/mod.rs index f023f32e..a48560b1 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -9,11 +9,7 @@ pub mod ui_registration; use bevy_egui::{EguiContext, EguiContexts}; use bevy_inspector_egui::{quick::WorldInspectorPlugin, DefaultInspectorConfigPlugin}; -use bevy_mod_picking::{ - backends::raycast::{RaycastPickable}, - prelude::*, - PickableBundle, -}; +use bevy_mod_picking::{backends::raycast::RaycastPickable, prelude::*, PickableBundle}; use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraSystemSet}; use crate::{ From 9443ed0e5ffc5a2967120f0dbc0dbb947d710e5d Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 23:36:20 +0300 Subject: [PATCH 10/35] Del shortcut --- src/editor/ui/settings.rs | 4 ++++ src/editor/ui/tools/gizmo.rs | 19 ++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index aeb42b55..e956f605 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -47,6 +47,10 @@ impl EditorTab for SettingsWindow { ui.label("Clone object"); ui.label("Alt"); ui.end_row(); + + ui.label("Delete object"); + ui.label("Delete or X"); + ui.end_row(); }); } diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index ceeb8006..7d531717 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, render::camera::CameraProjection}; +use bevy::{prelude::*, render::camera::CameraProjection, ecs::system::CommandQueue}; use bevy_egui::egui::{self, Key}; use egui_gizmo::*; @@ -48,6 +48,8 @@ impl EditorTool for GizmoTool { } } + let mut del = false; + if ui.ui_contains_pointer() && !ui.ctx().wants_keyboard_input() { //hot keys. Blender keys preffer let mode2key = vec![ @@ -61,6 +63,21 @@ impl EditorTool for GizmoTool { self.gizmo_mode = mode; } } + + if ui.input(|s| s.key_pressed(Key::Delete) || s.key_pressed(Key::X)) { + del = true; + } + } + + if del { + let mut command_queue = CommandQueue::default(); + let mut query = world.query_filtered::>(); + let mut commands = Commands::new(&mut command_queue, &world); + for e in query.iter(world) { + commands.entity(e).despawn_recursive(); + } + command_queue.apply(world); + return; } let (cam_transform, cam_proj) = { From 77dcbf073bcb669ebd002352f0691266f0ec8077 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 11 Nov 2023 23:54:53 +0300 Subject: [PATCH 11/35] Added commands to tools and tabs traits --- src/editor/core/tool.rs | 2 +- src/editor/ui/debug_panels.rs | 2 +- src/editor/ui/editor_tab.rs | 19 +++++----- src/editor/ui/game_view.rs | 4 +-- src/editor/ui/inspector/mod.rs | 2 +- src/editor/ui/mod.rs | 64 ++++++++++++++++++++-------------- src/editor/ui/settings.rs | 2 +- src/editor/ui/tools/gizmo.rs | 5 +-- 8 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/editor/core/tool.rs b/src/editor/core/tool.rs index ab7e3916..810a0d32 100644 --- a/src/editor/core/tool.rs +++ b/src/editor/core/tool.rs @@ -3,7 +3,7 @@ use bevy::prelude::*; use crate::prelude::GameViewTab; pub trait EditorTool { - fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, world: &mut World); + fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands : &mut Commands, world: &mut World); fn name(&self) -> &str; } diff --git a/src/editor/ui/debug_panels.rs b/src/editor/ui/debug_panels.rs index 05623edd..dc494595 100644 --- a/src/editor/ui/debug_panels.rs +++ b/src/editor/ui/debug_panels.rs @@ -6,7 +6,7 @@ use bevy_inspector_egui::*; pub struct DebugWorldInspector {} impl EditorTab for DebugWorldInspector { - fn ui(&mut self, ui: &mut egui::Ui, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _ : &mut Commands, world: &mut World) { bevy_inspector_egui::bevy_inspector::ui_for_world(world, ui); } diff --git a/src/editor/ui/editor_tab.rs b/src/editor/ui/editor_tab.rs index cbd372e5..1c4a58b7 100644 --- a/src/editor/ui/editor_tab.rs +++ b/src/editor/ui/editor_tab.rs @@ -6,7 +6,7 @@ use bevy_egui::egui::{self, WidgetText}; use super::{EditorUiRef, EditorUiReg}; pub trait EditorTab { - fn ui(&mut self, ui: &mut egui::Ui, world: &mut World); + fn ui(&mut self, ui: &mut egui::Ui, commands : &mut Commands, world: &mut World); fn title(&self) -> egui::WidgetText; } @@ -20,7 +20,7 @@ pub enum EditorTabName { Other(String), } -pub type EditorTabShowFn = Box; +pub type EditorTabShowFn = Box; pub type EditorTabGetTitleFn = Box WidgetText + Send + Sync>; pub enum EditorTabCommand { @@ -31,14 +31,15 @@ pub enum EditorTabCommand { }, } -pub struct EditorTabViewer<'a> { +pub struct EditorTabViewer<'a, 'w, 's> { pub world: &'a mut World, + pub commands : &'a mut Commands<'w,'s>, pub registry: &'a mut HashMap, pub visible: Vec, - pub commands: Vec, + pub tab_commands: Vec, } -impl<'a> egui_dock::TabViewer for EditorTabViewer<'a> { +impl<'a, 'w, 's> egui_dock::TabViewer for EditorTabViewer<'a, 'w, 's> { type Tab = EditorTabName; fn ui(&mut self, ui: &mut egui::Ui, tab_name: &mut Self::Tab) { @@ -48,13 +49,13 @@ impl<'a> egui_dock::TabViewer for EditorTabViewer<'a> { show_command, title_command: _, } => { - show_command(ui, self.world); + show_command(ui, self.commands, self.world); } EditorUiReg::Schedule => { self.world.resource_scope( |world, mut storage: Mut| { if let Some(tab) = storage.0.get_mut(tab_name) { - tab.ui(ui, world); + tab.ui(ui, self.commands, world); } else { ui.colored_label( egui::Color32::RED, @@ -117,7 +118,7 @@ impl<'a> egui_dock::TabViewer for EditorTabViewer<'a> { format_name = format!("{:?}", reg.0); } if ui.button(format_name).clicked() { - self.commands.push(EditorTabCommand::Add { + self.tab_commands.push(EditorTabCommand::Add { name: reg.0.clone(), surface: _surface, node: _node, @@ -139,7 +140,7 @@ pub struct ScheduleEditorTab { } impl EditorTab for ScheduleEditorTab { - fn ui(&mut self, ui: &mut egui::Ui, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _ : &mut Commands, world: &mut World) { let inner_ui = ui.child_ui(ui.max_rect(), *ui.layout()); world.insert_non_send_resource(EditorUiRef(inner_ui)); diff --git a/src/editor/ui/game_view.rs b/src/editor/ui/game_view.rs index df29db9e..3c096565 100644 --- a/src/editor/ui/game_view.rs +++ b/src/editor/ui/game_view.rs @@ -26,7 +26,7 @@ impl Default for GameViewTab { } impl EditorTab for GameViewTab { - fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, world: &mut World) { + fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands : &mut Commands, world: &mut World) { self.viewport_rect = Some(ui.clip_rect()); //Draw FPS @@ -63,7 +63,7 @@ impl EditorTab for GameViewTab { }); if let Some(tool_id) = self.active_tool { - self.tools[tool_id].ui(ui, world); + self.tools[tool_id].ui(ui, commands, world); } } diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index 02a0d5ae..fe854ccd 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -55,7 +55,7 @@ impl Plugin for SpaceInspectorPlugin { pub struct InspectorTab {} impl EditorTab for InspectorTab { - fn ui(&mut self, ui: &mut egui::Ui, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _ : &mut Commands, world: &mut World) { inspect(ui, world); } diff --git a/src/editor/ui/mod.rs b/src/editor/ui/mod.rs index 878e7bcb..fa9cecb5 100644 --- a/src/editor/ui/mod.rs +++ b/src/editor/ui/mod.rs @@ -27,7 +27,7 @@ pub use tools::*; pub mod debug_panels; -use bevy::{prelude::*, utils::HashMap, window::PrimaryWindow}; +use bevy::{prelude::*, utils::HashMap, window::PrimaryWindow, ecs::system::CommandQueue}; use bevy_egui::{egui, EguiContext}; use crate::{EditorSet, EditorState}; @@ -180,33 +180,43 @@ impl EditorUi { } } - let mut tab_viewer = EditorTabViewer { - world, - registry: &mut self.registry, - visible, - commands: vec![], - }; - - DockArea::new(&mut self.tree) - .show_add_buttons(true) - .show_add_popup(true) - .show(ctx, &mut tab_viewer); - - for command in tab_viewer.commands { - match command { - EditorTabCommand::Add { - name, - surface, - node, - } => { - if let Some(surface) = self.tree.get_surface_mut(surface) { - surface - .node_tree_mut() - .unwrap() - .split_right(node, 0.5, vec![name]); + let cell = world.as_unsafe_world_cell(); + + unsafe { + let mut command_queue = CommandQueue::default(); + let mut commands = Commands::new(&mut command_queue, cell.world()); + + let mut tab_viewer = EditorTabViewer { + commands : &mut commands, + world : cell.world_mut(), + registry: &mut self.registry, + visible, + tab_commands: vec![], + }; + + DockArea::new(&mut self.tree) + .show_add_buttons(true) + .show_add_popup(true) + .show(ctx, &mut tab_viewer); + + for command in tab_viewer.tab_commands { + match command { + EditorTabCommand::Add { + name, + surface, + node, + } => { + if let Some(surface) = self.tree.get_surface_mut(surface) { + surface + .node_tree_mut() + .unwrap() + .split_right(node, 0.5, vec![name]); + } } } } + + command_queue.apply(cell.world_mut()); } } } @@ -229,8 +239,8 @@ impl EditorUiAppExt for App { T: EditorTab + Resource + Send + Sync + 'static, { self.insert_resource(tab); - let show_fn = Box::new(|ui: &mut egui::Ui, world: &mut World| { - world.resource_scope(|scoped_world, mut data: Mut| data.ui(ui, scoped_world)); + let show_fn = Box::new(|ui: &mut egui::Ui, commands : &mut Commands, world: &mut World| { + world.resource_scope(|scoped_world, mut data: Mut| data.ui(ui, commands, scoped_world)); }); let reg = EditorUiReg::ResourceBased { show_command: show_fn, diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index e956f605..beea637e 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -17,7 +17,7 @@ impl Plugin for SettingsWindowPlugin { pub struct SettingsWindow {} impl EditorTab for SettingsWindow { - fn ui(&mut self, ui: &mut egui::Ui, _world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _commands : &mut Commands, _world: &mut World) { ui.heading("Hotkeys in Game view tab"); egui::Grid::new("hotkeys") diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 7d531717..32bc3b9c 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -27,7 +27,7 @@ impl EditorTool for GizmoTool { "Gizmo" } - fn ui(&mut self, ui: &mut egui::Ui, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, commands : &mut Commands, world: &mut World) { // GIZMO DRAW // Draw gizmo per entity to individual move // If SHIFT pressed draw "mean" gizmo to move all selected entities together @@ -70,13 +70,10 @@ impl EditorTool for GizmoTool { } if del { - let mut command_queue = CommandQueue::default(); let mut query = world.query_filtered::>(); - let mut commands = Commands::new(&mut command_queue, &world); for e in query.iter(world) { commands.entity(e).despawn_recursive(); } - command_queue.apply(world); return; } From d9ebd0c09ace204c35946d8114a2552bf21c27d1 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 12:42:14 +0300 Subject: [PATCH 12/35] Sorted names in inspector and fix xpbd debug render --- src/editor/mod.rs | 7 +- src/editor/ui/inspector/mod.rs | 53 ++++---------- src/editor/ui/settings.rs | 10 ++- src/optional/bevy_xpbd_plugin/mod.rs | 8 +++ .../bevy_xpbd_plugin/spatial_query.rs | 72 ------------------- 5 files changed, 36 insertions(+), 114 deletions(-) diff --git a/src/editor/mod.rs b/src/editor/mod.rs index a48560b1..cf07d85a 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -15,7 +15,7 @@ use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraS use crate::{ prefab::{component::CameraPlay, save::SaveState}, prelude::GameViewTab, - EditorCameraMarker, EditorSet, EditorState, PrefabMarker, + EditorCameraMarker, EditorSet, EditorState, PrefabMarker, optional::bevy_xpbd_plugin, }; use ui_registration::*; @@ -39,6 +39,11 @@ impl Plugin for EditorPlugin { app.add_plugins(bevy_egui::EguiPlugin); } + #[cfg(feature = "bevy_xpbd_3d")] + { + app.add_plugins(bevy_xpbd_plugin::BevyXpbdEditorPlugin); + } + app.add_plugins(EventListenerPlugin::::default()); app.add_plugins(DefaultInspectorConfigPlugin) diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index fe854ccd..ffb0148e 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -40,10 +40,6 @@ impl Plugin for SpaceInspectorPlugin { crate::prelude::EditorTabName::Inspector, InspectorTab::default(), ); - // app.add_systems(Update, (inspect, execute_inspect_command).chain() - // .after(crate::editor::reset_pan_orbit_state) - // .before(crate::editor::ui_camera_block) - // .in_set(EditorSet::Editor).before(PrefabSet::DetectPrefabChange)); app.add_systems(Update, execute_inspect_command); @@ -140,17 +136,17 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { let world_registry = app_registry.read(); let disable_pan_orbit = false; - let mut components_id = Vec::new(); - let mut types_id = Vec::new(); - let mut components_by_entity: HashMap> = HashMap::new(); - let mut types_by_entity: HashMap> = HashMap::new(); + //Collet data about all components + let mut components_id = Vec::new(); for reg in registry.iter() { if let Some(c_id) = world.components().get_id(reg.type_id()) { - components_id.push(c_id); - types_id.push(reg.type_id()); + let name = pretty_type_name::pretty_type_name_str(world.components().get_info(c_id).unwrap().name()); + components_id.push((c_id, reg.type_id(), name)); } } + components_id.sort_by(|a, b| a.2.cmp(&b.2)); + unsafe { let cell = world.as_unsafe_world_cell(); @@ -180,22 +176,9 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { ui.label("Components:"); let e_id = e.id().index(); egui::Grid::new(format!("{e_id}")).show(ui, |ui| { - for idx in 0..components_id.len() { - let c_id: ComponentId = components_by_entity - .entry(e_id) - .or_insert(Vec::new()) - .get(idx) - .copied() - .unwrap_or(components_id[idx]); - let t_id = types_by_entity - .entry(e_id) - .or_insert(Vec::new()) - .get(idx) - .copied() - .unwrap_or(types_id[idx]); - - if let Some(data) = e.get_mut_by_id(c_id) { - let registration = registry.get(t_id).unwrap(); + for (c_id, t_id, name) in &components_id { + if let Some(data) = e.get_mut_by_id(*c_id) { + let registration = registry.get(*t_id).unwrap(); if let Some(reflect_from_ptr) = registration.data::() { @@ -203,14 +186,9 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { let value = reflect_from_ptr.from_ptr_mut()(ptr); - let name = { - let info = cell.components().get_info(c_id).unwrap(); - pretty_type_name::pretty_type_name_str(info.name()) - }; - if !editor_registry.silent.contains(®istration.type_id()) { ui.push_id(format!("{:?}-{}", &e.id(), &name), |ui| { - ui.collapsing(&name, |ui| { + ui.collapsing(name, |ui| { ui.push_id( format!("content-{:?}-{}", &e.id(), &name), |ui| { @@ -238,7 +216,7 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { commands.push( InspectCommand::RemoveComponent( e.id(), - t_id, + *t_id, ), ); } @@ -264,17 +242,12 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { egui::Grid::new("Component grid").show(ui, |ui| { let _counter = 0; for idx in 0..components_id.len() { - let c_id = components_id[idx]; - let _t_id = types_id[idx]; - let name = pretty_type_name::pretty_type_name_str( - cell.components().get_info(c_id).unwrap().name(), - ); - + let (c_id, _t_id, name) = &components_id[idx]; if name.to_lowercase().contains(&lower_filter) { ui.label(name); if ui.button("+").clicked() { let id = - cell.components().get_info(c_id).unwrap().type_id().unwrap(); + cell.components().get_info(*c_id).unwrap().type_id().unwrap(); for e in selected.iter() { commands.push(InspectCommand::AddComponent(*e, id)); } diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index beea637e..779242ec 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -17,7 +17,15 @@ impl Plugin for SettingsWindowPlugin { pub struct SettingsWindow {} impl EditorTab for SettingsWindow { - fn ui(&mut self, ui: &mut egui::Ui, _commands : &mut Commands, _world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _commands : &mut Commands, world: &mut World) { + + #[cfg(feature = "bevy_xpbd_3d")] + { + ui.heading("Bevy XPBD 3D"); + ui.checkbox(&mut world.resource_mut::().enabled, "Show bevy xpbd debug render"); + ui.checkbox(&mut world.resource_mut::().hide_meshes, "Hide debug meshes"); + } + ui.heading("Hotkeys in Game view tab"); egui::Grid::new("hotkeys") diff --git a/src/optional/bevy_xpbd_plugin/mod.rs b/src/optional/bevy_xpbd_plugin/mod.rs index fc0c1bb4..d3c212c5 100644 --- a/src/optional/bevy_xpbd_plugin/mod.rs +++ b/src/optional/bevy_xpbd_plugin/mod.rs @@ -80,6 +80,14 @@ impl Plugin for BevyXpbdPlugin { } } +pub struct BevyXpbdEditorPlugin; + +impl Plugin for BevyXpbdEditorPlugin { + fn build(&self, app: &mut App) { + app.add_plugins(bevy_xpbd_3d::plugins::PhysicsDebugPlugin::default()); + } +} + fn sync_position_spawn( mut commands: Commands, query: Query< diff --git a/src/optional/bevy_xpbd_plugin/spatial_query.rs b/src/optional/bevy_xpbd_plugin/spatial_query.rs index c5babe5f..1e5e2776 100644 --- a/src/optional/bevy_xpbd_plugin/spatial_query.rs +++ b/src/optional/bevy_xpbd_plugin/spatial_query.rs @@ -9,21 +9,8 @@ use super::{collider::ColliderPrimitive, Vector}; pub fn register_xpbd_spatial_types(app: &mut App) { app.editor_registry::(); app.editor_into_sync::(); - app.add_systems( - Update, - draw_ray_caster - .in_set(EditorSet::Editor) - .run_if(in_state(EditorState::Editor)), - ); - app.editor_registry::(); app.editor_into_sync::(); - app.add_systems( - Update, - draw_shapecast - .in_set(EditorSet::Editor) - .run_if(in_state(EditorState::Editor)), - ); } #[derive(Component, Reflect, Clone, Debug, InspectorOptions)] @@ -48,36 +35,6 @@ impl From for RayCaster { } } -//debug in editor draw -fn draw_ray_caster(mut gizmos: Gizmos, query: Query<(&RayCaster, &RayHits)>) { - for (ray, hits) in query.iter() { - let global_origin = ray.global_origin(); - let global_direction = ray.global_direction(); - for hit in hits.iter() { - gizmos.line( - global_origin, - global_origin + global_direction * hit.time_of_impact, - Color::PURPLE, - ); - gizmos.sphere( - global_origin + global_direction * hit.time_of_impact, - Quat::IDENTITY, - 0.1, - Color::PURPLE, - ); - } - - if hits.is_empty() { - let inf_color = Color::GRAY; - gizmos.line( - global_origin, - global_origin + global_direction * 1000.0, - inf_color, - ); - } - } -} - #[derive(Component, Reflect, Clone, Debug, InspectorOptions, Default)] #[reflect(Component, Default)] pub struct ShapeCasterPrefab { @@ -98,32 +55,3 @@ impl From for ShapeCaster { .with_ignore_origin_penetration(true) } } - -fn draw_shapecast(mut gizmos: Gizmos, query: Query<(&ShapeCaster, &ShapeHits)>) { - for (caster, hits) in query.iter() { - let global_origin = caster.global_origin(); - let global_direction = caster.global_direction(); - for hit in hits.iter() { - gizmos.line( - global_origin, - global_origin + global_direction * hit.time_of_impact, - Color::PURPLE, - ); - gizmos.sphere( - global_origin + global_direction * hit.time_of_impact, - Quat::IDENTITY, - 0.1, - Color::PURPLE, - ); - } - - if hits.is_empty() { - let inf_color = Color::GRAY; - gizmos.line( - global_origin, - global_origin + global_direction * 1000.0, - inf_color, - ); - } - } -} From ca0db4d97bff2303da1e19885daa62a0482af73b Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 12:42:47 +0300 Subject: [PATCH 13/35] cargo fmt --- src/editor/core/tool.rs | 2 +- src/editor/mod.rs | 3 ++- src/editor/ui/debug_panels.rs | 2 +- src/editor/ui/editor_tab.rs | 6 +++--- src/editor/ui/game_view.rs | 2 +- src/editor/ui/inspector/mod.rs | 18 +++++++++++------- src/editor/ui/mod.rs | 16 ++++++++++------ src/editor/ui/settings.rs | 17 +++++++++++++---- src/editor/ui/tools/gizmo.rs | 4 ++-- 9 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/editor/core/tool.rs b/src/editor/core/tool.rs index 810a0d32..8aa8465c 100644 --- a/src/editor/core/tool.rs +++ b/src/editor/core/tool.rs @@ -3,7 +3,7 @@ use bevy::prelude::*; use crate::prelude::GameViewTab; pub trait EditorTool { - fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands : &mut Commands, world: &mut World); + fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands: &mut Commands, world: &mut World); fn name(&self) -> &str; } diff --git a/src/editor/mod.rs b/src/editor/mod.rs index cf07d85a..c74f16cd 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -13,9 +13,10 @@ use bevy_mod_picking::{backends::raycast::RaycastPickable, prelude::*, PickableB use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraSystemSet}; use crate::{ + optional::bevy_xpbd_plugin, prefab::{component::CameraPlay, save::SaveState}, prelude::GameViewTab, - EditorCameraMarker, EditorSet, EditorState, PrefabMarker, optional::bevy_xpbd_plugin, + EditorCameraMarker, EditorSet, EditorState, PrefabMarker, }; use ui_registration::*; diff --git a/src/editor/ui/debug_panels.rs b/src/editor/ui/debug_panels.rs index dc494595..e9af786e 100644 --- a/src/editor/ui/debug_panels.rs +++ b/src/editor/ui/debug_panels.rs @@ -6,7 +6,7 @@ use bevy_inspector_egui::*; pub struct DebugWorldInspector {} impl EditorTab for DebugWorldInspector { - fn ui(&mut self, ui: &mut egui::Ui, _ : &mut Commands, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _: &mut Commands, world: &mut World) { bevy_inspector_egui::bevy_inspector::ui_for_world(world, ui); } diff --git a/src/editor/ui/editor_tab.rs b/src/editor/ui/editor_tab.rs index 1c4a58b7..83a0f6de 100644 --- a/src/editor/ui/editor_tab.rs +++ b/src/editor/ui/editor_tab.rs @@ -6,7 +6,7 @@ use bevy_egui::egui::{self, WidgetText}; use super::{EditorUiRef, EditorUiReg}; pub trait EditorTab { - fn ui(&mut self, ui: &mut egui::Ui, commands : &mut Commands, world: &mut World); + fn ui(&mut self, ui: &mut egui::Ui, commands: &mut Commands, world: &mut World); fn title(&self) -> egui::WidgetText; } @@ -33,7 +33,7 @@ pub enum EditorTabCommand { pub struct EditorTabViewer<'a, 'w, 's> { pub world: &'a mut World, - pub commands : &'a mut Commands<'w,'s>, + pub commands: &'a mut Commands<'w, 's>, pub registry: &'a mut HashMap, pub visible: Vec, pub tab_commands: Vec, @@ -140,7 +140,7 @@ pub struct ScheduleEditorTab { } impl EditorTab for ScheduleEditorTab { - fn ui(&mut self, ui: &mut egui::Ui, _ : &mut Commands, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _: &mut Commands, world: &mut World) { let inner_ui = ui.child_ui(ui.max_rect(), *ui.layout()); world.insert_non_send_resource(EditorUiRef(inner_ui)); diff --git a/src/editor/ui/game_view.rs b/src/editor/ui/game_view.rs index 3c096565..bd8cc4e9 100644 --- a/src/editor/ui/game_view.rs +++ b/src/editor/ui/game_view.rs @@ -26,7 +26,7 @@ impl Default for GameViewTab { } impl EditorTab for GameViewTab { - fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands : &mut Commands, world: &mut World) { + fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands: &mut Commands, world: &mut World) { self.viewport_rect = Some(ui.clip_rect()); //Draw FPS diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index ffb0148e..3a5e0ead 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -51,7 +51,7 @@ impl Plugin for SpaceInspectorPlugin { pub struct InspectorTab {} impl EditorTab for InspectorTab { - fn ui(&mut self, ui: &mut egui::Ui, _ : &mut Commands, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, _: &mut Commands, world: &mut World) { inspect(ui, world); } @@ -136,17 +136,17 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { let world_registry = app_registry.read(); let disable_pan_orbit = false; - //Collet data about all components let mut components_id = Vec::new(); for reg in registry.iter() { if let Some(c_id) = world.components().get_id(reg.type_id()) { - let name = pretty_type_name::pretty_type_name_str(world.components().get_info(c_id).unwrap().name()); + let name = pretty_type_name::pretty_type_name_str( + world.components().get_info(c_id).unwrap().name(), + ); components_id.push((c_id, reg.type_id(), name)); } } components_id.sort_by(|a, b| a.2.cmp(&b.2)); - unsafe { let cell = world.as_unsafe_world_cell(); @@ -176,7 +176,7 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { ui.label("Components:"); let e_id = e.id().index(); egui::Grid::new(format!("{e_id}")).show(ui, |ui| { - for (c_id, t_id, name) in &components_id { + for (c_id, t_id, name) in &components_id { if let Some(data) = e.get_mut_by_id(*c_id) { let registration = registry.get(*t_id).unwrap(); if let Some(reflect_from_ptr) = @@ -246,8 +246,12 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { if name.to_lowercase().contains(&lower_filter) { ui.label(name); if ui.button("+").clicked() { - let id = - cell.components().get_info(*c_id).unwrap().type_id().unwrap(); + let id = cell + .components() + .get_info(*c_id) + .unwrap() + .type_id() + .unwrap(); for e in selected.iter() { commands.push(InspectCommand::AddComponent(*e, id)); } diff --git a/src/editor/ui/mod.rs b/src/editor/ui/mod.rs index fa9cecb5..851f111d 100644 --- a/src/editor/ui/mod.rs +++ b/src/editor/ui/mod.rs @@ -27,7 +27,7 @@ pub use tools::*; pub mod debug_panels; -use bevy::{prelude::*, utils::HashMap, window::PrimaryWindow, ecs::system::CommandQueue}; +use bevy::{ecs::system::CommandQueue, prelude::*, utils::HashMap, window::PrimaryWindow}; use bevy_egui::{egui, EguiContext}; use crate::{EditorSet, EditorState}; @@ -187,8 +187,8 @@ impl EditorUi { let mut commands = Commands::new(&mut command_queue, cell.world()); let mut tab_viewer = EditorTabViewer { - commands : &mut commands, - world : cell.world_mut(), + commands: &mut commands, + world: cell.world_mut(), registry: &mut self.registry, visible, tab_commands: vec![], @@ -239,9 +239,13 @@ impl EditorUiAppExt for App { T: EditorTab + Resource + Send + Sync + 'static, { self.insert_resource(tab); - let show_fn = Box::new(|ui: &mut egui::Ui, commands : &mut Commands, world: &mut World| { - world.resource_scope(|scoped_world, mut data: Mut| data.ui(ui, commands, scoped_world)); - }); + let show_fn = Box::new( + |ui: &mut egui::Ui, commands: &mut Commands, world: &mut World| { + world.resource_scope(|scoped_world, mut data: Mut| { + data.ui(ui, commands, scoped_world) + }); + }, + ); let reg = EditorUiReg::ResourceBased { show_command: show_fn, title_command: Box::new(|world| world.resource_mut::().title()), diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index 779242ec..2e50e184 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -17,13 +17,22 @@ impl Plugin for SettingsWindowPlugin { pub struct SettingsWindow {} impl EditorTab for SettingsWindow { - fn ui(&mut self, ui: &mut egui::Ui, _commands : &mut Commands, world: &mut World) { - + fn ui(&mut self, ui: &mut egui::Ui, _commands: &mut Commands, world: &mut World) { #[cfg(feature = "bevy_xpbd_3d")] { ui.heading("Bevy XPBD 3D"); - ui.checkbox(&mut world.resource_mut::().enabled, "Show bevy xpbd debug render"); - ui.checkbox(&mut world.resource_mut::().hide_meshes, "Hide debug meshes"); + ui.checkbox( + &mut world + .resource_mut::() + .enabled, + "Show bevy xpbd debug render", + ); + ui.checkbox( + &mut world + .resource_mut::() + .hide_meshes, + "Hide debug meshes", + ); } ui.heading("Hotkeys in Game view tab"); diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 32bc3b9c..2d670f45 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, render::camera::CameraProjection, ecs::system::CommandQueue}; +use bevy::{ecs::system::CommandQueue, prelude::*, render::camera::CameraProjection}; use bevy_egui::egui::{self, Key}; use egui_gizmo::*; @@ -27,7 +27,7 @@ impl EditorTool for GizmoTool { "Gizmo" } - fn ui(&mut self, ui: &mut egui::Ui, commands : &mut Commands, world: &mut World) { + fn ui(&mut self, ui: &mut egui::Ui, commands: &mut Commands, world: &mut World) { // GIZMO DRAW // Draw gizmo per entity to individual move // If SHIFT pressed draw "mean" gizmo to move all selected entities together From 978ad62f8fa965b3e0e1110d47bae7d126b2cd12 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 12:45:15 +0300 Subject: [PATCH 14/35] Cargo clippy --- src/editor/ui/inspector/mod.rs | 6 ++---- src/editor/ui/tools/gizmo.rs | 2 +- src/optional/bevy_xpbd_plugin/spatial_query.rs | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index 3a5e0ead..e2d6caca 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -3,11 +3,10 @@ pub mod refl_impl; use std::any::TypeId; use bevy::{ - ecs::{change_detection::MutUntyped, component::ComponentId, system::CommandQueue}, + ecs::{change_detection::MutUntyped, system::CommandQueue}, prelude::*, ptr::PtrMut, reflect::ReflectFromPtr, - utils::HashMap, }; use bevy_egui::*; @@ -241,8 +240,7 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { egui::ScrollArea::vertical().show(ui, |ui| { egui::Grid::new("Component grid").show(ui, |ui| { let _counter = 0; - for idx in 0..components_id.len() { - let (c_id, _t_id, name) = &components_id[idx]; + for (c_id, _t_id, name) in &components_id { if name.to_lowercase().contains(&lower_filter) { ui.label(name); if ui.button("+").clicked() { diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 2d670f45..f3d8495a 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -1,4 +1,4 @@ -use bevy::{ecs::system::CommandQueue, prelude::*, render::camera::CameraProjection}; +use bevy::{prelude::*, render::camera::CameraProjection}; use bevy_egui::egui::{self, Key}; use egui_gizmo::*; diff --git a/src/optional/bevy_xpbd_plugin/spatial_query.rs b/src/optional/bevy_xpbd_plugin/spatial_query.rs index 1e5e2776..58f1ac3a 100644 --- a/src/optional/bevy_xpbd_plugin/spatial_query.rs +++ b/src/optional/bevy_xpbd_plugin/spatial_query.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use bevy_inspector_egui::*; use bevy_xpbd_3d::{math::Quaternion, prelude::*}; -use crate::{prelude::EditorRegistryExt, EditorSet, EditorState}; +use crate::prelude::EditorRegistryExt; use super::{collider::ColliderPrimitive, Vector}; From 294fc76abd008d70e43979bc91d0907eb21aeee5 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 12:48:27 +0300 Subject: [PATCH 15/35] Fix compiling without features --- src/editor/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/editor/mod.rs b/src/editor/mod.rs index c74f16cd..4466a803 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -13,7 +13,6 @@ use bevy_mod_picking::{backends::raycast::RaycastPickable, prelude::*, PickableB use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin, PanOrbitCameraSystemSet}; use crate::{ - optional::bevy_xpbd_plugin, prefab::{component::CameraPlay, save::SaveState}, prelude::GameViewTab, EditorCameraMarker, EditorSet, EditorState, PrefabMarker, @@ -42,7 +41,7 @@ impl Plugin for EditorPlugin { #[cfg(feature = "bevy_xpbd_3d")] { - app.add_plugins(bevy_xpbd_plugin::BevyXpbdEditorPlugin); + app.add_plugins(crate::optional::bevy_xpbd_plugin::BevyXpbdEditorPlugin); } app.add_plugins(EventListenerPlugin::::default()); From 16faa52bab446519aff71518baf38a52022fe5b7 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 18:22:36 +0300 Subject: [PATCH 16/35] Persistance logic --- Cargo.toml | 1 + src/editor/core/mod.rs | 4 +- src/editor/core/persistance.rs | 210 +++++++++++++++++++++++++++++++++ src/editor/core/settings.rs | 1 - 4 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 src/editor/core/persistance.rs delete mode 100644 src/editor/core/settings.rs diff --git a/Cargo.toml b/Cargo.toml index a0f545bf..b12e1c17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ bevy_egui = "0.23" egui-gizmo = "0.12" bevy-scene-hook = "9" ron = "0.8" +serde = "1" bevy_panorbit_camera = "0.9" bevy-inspector-egui = {version = "0.21", features = ["bevy_pbr", "highlight_changes"]} pretty-type-name = "1.0" diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index 700475c1..a3eb3978 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -7,8 +7,8 @@ use load::*; pub mod tool; pub use tool::*; -pub mod settings; -pub use settings::*; +pub mod persistance; +pub use persistance::*; pub mod gltf_unpack; diff --git a/src/editor/core/persistance.rs b/src/editor/core/persistance.rs new file mode 100644 index 00000000..8792db2a --- /dev/null +++ b/src/editor/core/persistance.rs @@ -0,0 +1,210 @@ +// This part of code is used for saving and loading settings and window state + +use std::any::TypeId; + +use bevy::{prelude::*, utils::HashMap, reflect::{TypeRegistry, serde::{ReflectSerializer, TypedReflectDeserializer, UntypedReflectDeserializer}, GetTypeRegistration}}; +use ron::{*, ser::PrettyConfig}; +use serde::de::DeserializeSeed; + +pub struct PersistancePlugin; + +#[derive(SystemSet, Hash, PartialEq, Clone, Debug, Eq)] +pub enum PersistanceSet { + EventReader, + ResourceProcess, + Collect +} + +impl Plugin for PersistancePlugin { + fn build(&self, app: &mut App) { + app + .init_resource::(); + + app.add_event::(); + app.configure_sets(Update, ( + PersistanceSet::EventReader, + PersistanceSet::ResourceProcess, + PersistanceSet::Collect + ).chain()); + + app.add_systems(Update, persistance_start.in_set(PersistanceSet::EventReader)); + app.add_systems(Update, persistance_end.in_set(PersistanceSet::Collect)); + } +} + +fn persistance_start( + mut events: EventReader, + mut broadcast : EventWriter, + mut persistance : ResMut +) { + for event in events.read() { + match event { + PersistanceEvent::Save => { + broadcast.send(PersistanceResourceBroadcastEvent::Pack); + persistance.mode = PersistanceMode::Saving; + persistance.save_counter = 0; + }, + PersistanceEvent::Load => { + + match &persistance.source { + PersistanceDataSource::File(path) => { + let file = std::fs::File::open(path).unwrap(); + let data: HashMap = ron::de::from_reader(file).unwrap(); + persistance.data = data; + }, + PersistanceDataSource::Memory => { + //do nothing + }, + } + + broadcast.send(PersistanceResourceBroadcastEvent::Unpack); + persistance.mode = PersistanceMode::Loading; + persistance.load_counter = 0; + }, + } + } +} + +fn persistance_end( + mut persistance : ResMut, +) { + let mode = persistance.mode.clone(); + match mode { + PersistanceMode::Saving => { + persistance.mode = PersistanceMode::None; + if persistance.save_counter != persistance.target_count { + error!("Persistance saving error: {} of {} resources were saved", persistance.save_counter, persistance.target_count); + } + + match &persistance.source { + PersistanceDataSource::File(path) => { + let mut file = std::fs::File::create(path).unwrap(); + ron::ser::to_writer_pretty(&mut file, &persistance.data, PrettyConfig::default()).unwrap(); + }, + PersistanceDataSource::Memory => { + //do nothing + }, + } { + + } + }, + PersistanceMode::Loading => { + persistance.mode = PersistanceMode::None; + if persistance.load_counter == persistance.target_count { + error!("Persistance loading error: {} of {} resources were loaded", persistance.load_counter, persistance.target_count); + } + }, + _ => {} + + } +} + +/// ['PersistanceResource'] implements the simple mechanics of saving and loading editor state between runs +pub trait PersistanceResource : Default + Reflect + FromReflect + Resource + GetTypeRegistration { + +} + +#[derive(Default, Clone)] +enum PersistanceMode { + Saving, + Loading, + #[default] + None +} + +/// ['PersistanceRegistry'] contains lambda functions for loading/unloading editor state +/// At the moment of closing the window or starting the game mode, +/// all necessary data is saved to a file/memory, and then restored when the editor mode is opened. +/// When the restored resource is loaded, the ['PersistenceLoaded'] event is generated +/// +/// ['PersistenceLoaded']: crate::editor::core::persistance::PersistanceLoaded +#[derive(Resource, Default)] +pub struct PersistanceRegistry { + source : PersistanceDataSource, + data: HashMap, + load_counter: usize, + save_counter: usize, + target_count: usize, + mode: PersistanceMode +} + +#[derive(Event, Default)] +pub struct PersistanceLoaded { + _phantom: std::marker::PhantomData, +} + +#[derive(Event)] +pub enum PersistanceEvent { + Save, + Load, +} + + +#[derive(Event)] +enum PersistanceResourceBroadcastEvent { + Unpack, + Pack, +} + +pub enum PersistanceDataSource { + File(String), + Memory +} + +impl Default for PersistanceDataSource { + fn default() -> Self { + Self::File("editor.ron".to_string()) + } +} + + +pub trait AppPersistanceExt { + fn persistance_resource(&mut self) -> &mut Self; +} + +impl AppPersistanceExt for App { + fn persistance_resource(&mut self) -> &mut Self { + self.world.resource_mut::().target_count += 1; + + self.register_type::(); + self.add_event::>(); + + self.add_systems(Update, persistance_resource_system::.in_set(PersistanceSet::ResourceProcess)); + + self + } +} + + +fn persistance_resource_system( + mut events: EventReader, + mut persistance : ResMut, + mut resource : ResMut, + registry : Res, + mut persistance_loaded : EventWriter>, +) { + for event in events.read() { + match event { + PersistanceResourceBroadcastEvent::Pack => { + let type_registry = registry.read(); + let serializer = ReflectSerializer::new(resource.as_ref(), &type_registry); + let data = ron::to_string(&serializer).unwrap(); + persistance.data.insert(T::get_type_registration().type_info().type_path().to_string(), data); + persistance.save_counter += 1; + }, + PersistanceResourceBroadcastEvent::Unpack => { + let data = persistance.data.get(T::get_type_registration().type_info().type_path()).unwrap(); + let type_registry = registry.read(); + let deserializer = UntypedReflectDeserializer::new(&type_registry); + let reflected_value = deserializer.deserialize( + &mut ron::Deserializer::from_str(data).unwrap() + ).unwrap(); + + let converted = ::from_reflect(&*reflected_value).unwrap(); + *resource = converted; + persistance_loaded.send(PersistanceLoaded::::default()); + persistance.load_counter += 1; + }, + } + } +} \ No newline at end of file diff --git a/src/editor/core/settings.rs b/src/editor/core/settings.rs deleted file mode 100644 index 8b137891..00000000 --- a/src/editor/core/settings.rs +++ /dev/null @@ -1 +0,0 @@ - From 9ae1c8ca3de288a79eaeeed677f8442b3ec1a455 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 19:43:31 +0300 Subject: [PATCH 17/35] Hide persistance under feature --- .gitignore | 1 + Cargo.toml | 1 + src/editor/core/mod.rs | 5 +++ src/editor/core/persistance.rs | 79 ++++++++++++++++++++++++++++------ src/editor/mod.rs | 13 +++--- src/editor/ui/settings.rs | 14 ++++++ 6 files changed, 95 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 12127356..4660861a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ Cargo.lock docs/.obsidian/* .vscode/launch.json +editor.ron diff --git a/Cargo.toml b/Cargo.toml index b12e1c17..e92a1637 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ opt-level = 3 [features] bevy_xpbd_3d = ["dep:bevy_xpbd_3d", "bevy_xpbd_3d/debug-plugin", "bevy_xpbd_3d/3d", "bevy_xpbd_3d/collider-from-mesh", "bevy_xpbd_3d/f32"] +persistance_editor = [] [[example]] name = "platformer" diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index a3eb3978..3a42ae48 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -7,7 +7,9 @@ use load::*; pub mod tool; pub use tool::*; +#[cfg(feature = "persistance_editor")] pub mod persistance; +#[cfg(feature = "persistance_editor")] pub use persistance::*; pub mod gltf_unpack; @@ -26,6 +28,9 @@ impl Plugin for EditorCore { fn build(&self, app: &mut App) { app.add_plugins(gltf_unpack::UnpackGltfPlugin); + #[cfg(feature = "persistance_editor")] + app.add_plugins(PersistancePlugin); + app.add_event::(); app.init_resource::(); diff --git a/src/editor/core/persistance.rs b/src/editor/core/persistance.rs index 8792db2a..3992fea1 100644 --- a/src/editor/core/persistance.rs +++ b/src/editor/core/persistance.rs @@ -2,7 +2,7 @@ use std::any::TypeId; -use bevy::{prelude::*, utils::HashMap, reflect::{TypeRegistry, serde::{ReflectSerializer, TypedReflectDeserializer, UntypedReflectDeserializer}, GetTypeRegistration}}; +use bevy::{prelude::*, utils::HashMap, reflect::{TypeRegistry, serde::{ReflectSerializer, TypedReflectDeserializer, UntypedReflectDeserializer}, GetTypeRegistration}, window::WindowCloseRequested}; use ron::{*, ser::PrettyConfig}; use serde::de::DeserializeSeed; @@ -18,24 +18,55 @@ pub enum PersistanceSet { impl Plugin for PersistancePlugin { fn build(&self, app: &mut App) { app - .init_resource::(); + .init_resource::() + .init_resource::(); app.add_event::(); + app.add_event::(); + app.configure_sets(Update, ( PersistanceSet::EventReader, PersistanceSet::ResourceProcess, PersistanceSet::Collect ).chain()); + app.add_systems(Startup, persistance_startup_load); + app.add_systems(PreUpdate, persistance_save_on_close); + app.add_systems(Update, persistance_start.in_set(PersistanceSet::EventReader)); app.add_systems(Update, persistance_end.in_set(PersistanceSet::Collect)); + + app.persistance_resource::(); + } +} + +fn persistance_save_on_close( + mut events: EventWriter, + settings : Res, + mut close_events : EventReader, +) { + if settings.save_on_close { + if close_events.read().next().is_some() { + events.send(PersistanceEvent::Save); + } + } +} + +fn persistance_startup_load( + mut events: EventWriter, + settings : Res, +) { + if settings.load_on_startup { + events.send(PersistanceEvent::Load); } } + + fn persistance_start( mut events: EventReader, mut broadcast : EventWriter, - mut persistance : ResMut + mut persistance : ResMut, ) { for event in events.read() { match event { @@ -45,10 +76,12 @@ fn persistance_start( persistance.save_counter = 0; }, PersistanceEvent::Load => { - match &persistance.source { PersistanceDataSource::File(path) => { - let file = std::fs::File::open(path).unwrap(); + let Ok(file) = std::fs::File::open(path) else { + warn!("Persistance file not found"); + continue; + }; let data: HashMap = ron::de::from_reader(file).unwrap(); persistance.data = data; }, @@ -79,7 +112,10 @@ fn persistance_end( match &persistance.source { PersistanceDataSource::File(path) => { let mut file = std::fs::File::create(path).unwrap(); - ron::ser::to_writer_pretty(&mut file, &persistance.data, PrettyConfig::default()).unwrap(); + ron::ser::to_writer_pretty( + &mut file, + &persistance.data, + PrettyConfig::default()).unwrap(); }, PersistanceDataSource::Memory => { //do nothing @@ -99,9 +135,21 @@ fn persistance_end( } } -/// ['PersistanceResource'] implements the simple mechanics of saving and loading editor state between runs -pub trait PersistanceResource : Default + Reflect + FromReflect + Resource + GetTypeRegistration { +#[derive(Resource, Reflect)] +#[reflect(Resource)] +pub struct PersistanceSettings { + pub load_on_startup: bool, + pub save_on_close: bool, +} + +impl Default for PersistanceSettings { + fn default() -> Self { + Self { + load_on_startup: true, + save_on_close: true, + } + } } #[derive(Default, Clone)] @@ -146,6 +194,8 @@ enum PersistanceResourceBroadcastEvent { Pack, } +#[derive(Reflect, Clone)] +#[reflect(Default)] pub enum PersistanceDataSource { File(String), Memory @@ -159,11 +209,11 @@ impl Default for PersistanceDataSource { pub trait AppPersistanceExt { - fn persistance_resource(&mut self) -> &mut Self; + fn persistance_resource(&mut self) -> &mut Self; } impl AppPersistanceExt for App { - fn persistance_resource(&mut self) -> &mut Self { + fn persistance_resource(&mut self) -> &mut Self { self.world.resource_mut::().target_count += 1; self.register_type::(); @@ -176,7 +226,7 @@ impl AppPersistanceExt for App { } -fn persistance_resource_system( +fn persistance_resource_system( mut events: EventReader, mut persistance : ResMut, mut resource : ResMut, @@ -193,7 +243,10 @@ fn persistance_resource_system( persistance.save_counter += 1; }, PersistanceResourceBroadcastEvent::Unpack => { - let data = persistance.data.get(T::get_type_registration().type_info().type_path()).unwrap(); + let Some(data) = persistance.data.get(T::get_type_registration().type_info().type_path()) else { + warn!("Persistance resource {} not found", T::get_type_registration().type_info().type_path()); + continue; + }; let type_registry = registry.read(); let deserializer = UntypedReflectDeserializer::new(&type_registry); let reflected_value = deserializer.deserialize( @@ -202,6 +255,8 @@ fn persistance_resource_system( let converted = ::from_reflect(&*reflected_value).unwrap(); *resource = converted; + resource.set_changed(); + persistance_loaded.send(PersistanceLoaded::::default()); persistance.load_counter += 1; }, diff --git a/src/editor/mod.rs b/src/editor/mod.rs index 4466a803..5ef1187f 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -38,11 +38,8 @@ impl Plugin for EditorPlugin { if !app.is_plugin_added::() { app.add_plugins(bevy_egui::EguiPlugin); } + app.add_plugins(core::EditorCore); - #[cfg(feature = "bevy_xpbd_3d")] - { - app.add_plugins(crate::optional::bevy_xpbd_plugin::BevyXpbdEditorPlugin); - } app.add_plugins(EventListenerPlugin::::default()); @@ -65,8 +62,6 @@ impl Plugin for EditorPlugin { app.insert_resource(PanOrbitEnabled(true)); - app.add_plugins(core::EditorCore); - app.add_systems( Startup, (set_start_state, apply_state_transition::) @@ -129,6 +124,12 @@ impl Plugin for EditorPlugin { app.add_plugins(WorldInspectorPlugin::default().run_if(in_state(EditorState::Game))); + + #[cfg(feature = "bevy_xpbd_3d")] + { + app.add_plugins(crate::optional::bevy_xpbd_plugin::BevyXpbdEditorPlugin); + } + register_mesh_editor_bundles(app); register_light_editor_bundles(app); } diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index 2e50e184..93afab87 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -3,6 +3,9 @@ use bevy_egui::*; use crate::prelude::{EditorTab, EditorTabName}; +#[cfg(feature = "persistance_editor")] +use crate::prelude::editor::core::AppPersistanceExt; + use super::EditorUiAppExt; pub struct SettingsWindowPlugin; @@ -10,6 +13,17 @@ pub struct SettingsWindowPlugin; impl Plugin for SettingsWindowPlugin { fn build(&self, app: &mut App) { app.editor_tab_by_trait(EditorTabName::Settings, SettingsWindow::default()); + + #[cfg(feature = "bevy_xpbd_3d")] + { + #[cfg(feature = "persistance_editor")] { + app.persistance_resource::(); + app.register_type::>(); + app.register_type::>(); + app.register_type::>(); + app.register_type::<[f32; 4]>(); + } + } } } From e916423233075f2eb989359ad4ac0c6dfd60630c Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 21:37:38 +0300 Subject: [PATCH 18/35] Cache open states --- src/editor/ui/inspector/mod.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index e2d6caca..902413da 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -3,10 +3,10 @@ pub mod refl_impl; use std::any::TypeId; use bevy::{ - ecs::{change_detection::MutUntyped, system::CommandQueue}, + ecs::{change_detection::MutUntyped, system::CommandQueue, component::ComponentId}, prelude::*, ptr::PtrMut, - reflect::ReflectFromPtr, + reflect::ReflectFromPtr, utils::HashMap, }; use bevy_egui::*; @@ -47,11 +47,13 @@ impl Plugin for SpaceInspectorPlugin { } #[derive(Resource, Default)] -pub struct InspectorTab {} +pub struct InspectorTab { + default_opened : HashMap +} impl EditorTab for InspectorTab { fn ui(&mut self, ui: &mut egui::Ui, _: &mut Commands, world: &mut World) { - inspect(ui, world); + inspect(self, ui, world); } fn title(&self) -> egui::WidgetText { @@ -122,7 +124,7 @@ fn execute_inspect_command( } /// System to show inspector panel -pub fn inspect(ui: &mut egui::Ui, world: &mut World) { +pub fn inspect(tab : &mut InspectorTab, ui: &mut egui::Ui, world: &mut World) { let selected = world .query_filtered::>() .iter(world) @@ -187,7 +189,13 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { if !editor_registry.silent.contains(®istration.type_id()) { ui.push_id(format!("{:?}-{}", &e.id(), &name), |ui| { - ui.collapsing(name, |ui| { + let need_default_open = tab + .default_opened + .get(c_id) + .unwrap_or(&false) + .clone(); + let responce = egui::CollapsingHeader::new(name) + .default_open(need_default_open).show(ui, |ui| { ui.push_id( format!("content-{:?}-{}", &e.id(), &name), |ui| { @@ -202,6 +210,11 @@ pub fn inspect(ui: &mut egui::Ui, world: &mut World) { }, ); }); + if responce.fully_open() && !need_default_open { + tab.default_opened.insert(*c_id, true); + } else if responce.fully_closed() && need_default_open { + tab.default_opened.insert(*c_id, false); + } }); ui.push_id( From cae7bb16d041701a0c38ad8fa2d7d3542932be50 Mon Sep 17 00:00:00 2001 From: rewin Date: Sun, 12 Nov 2023 22:06:29 +0300 Subject: [PATCH 19/35] Loading indicator --- src/editor/core/gltf_unpack.rs | 10 +++++++- src/editor/core/mod.rs | 13 +++++++++- src/editor/core/task_storage.rs | 43 +++++++++++++++++++++++++++++++++ src/editor/ui/bot_menu.rs | 17 ++++++++++++- 4 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/editor/core/task_storage.rs diff --git a/src/editor/core/gltf_unpack.rs b/src/editor/core/gltf_unpack.rs index 560db208..4ba6ae2b 100644 --- a/src/editor/core/gltf_unpack.rs +++ b/src/editor/core/gltf_unpack.rs @@ -11,6 +11,8 @@ use crate::{ PrefabMarker, }; +use super::{BackgroundTaskStorage, BackgroundTask}; + #[derive(Event)] pub struct EditorUnpackGltf { pub path: String, @@ -47,9 +49,15 @@ fn unpack_gltf_event( mut events: EventReader, assets: Res, mut queue: ResMut, + mut background_tasks : ResMut, ) { for event in events.read() { - queue.0.push(assets.load(event.path.clone())); + let handle = assets.load(event.path.clone()); + background_tasks.tasks.push(BackgroundTask::AssetLoading( + event.path.clone(), + handle.clone().untyped(), + )); + queue.0.push(handle); } events.clear(); } diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index 3a42ae48..6bf88165 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -7,6 +7,9 @@ use load::*; pub mod tool; pub use tool::*; +pub mod task_storage; +pub use task_storage::*; + #[cfg(feature = "persistance_editor")] pub mod persistance; #[cfg(feature = "persistance_editor")] @@ -31,6 +34,8 @@ impl Plugin for EditorCore { #[cfg(feature = "persistance_editor")] app.add_plugins(PersistancePlugin); + app.add_plugins(BackgroundTaskStoragePlugin); + app.add_event::(); app.init_resource::(); @@ -74,12 +79,18 @@ fn editor_event_listener( mut start_game_state: ResMut>, cache: ResMut, mut gltf_events: EventWriter, + mut background_tasks : ResMut, ) { for event in events.read() { match event { EditorEvent::Load(path) => match path { EditorPrefabPath::File(path) => { - load_server.scene = Some(assets.load(path.to_string())) + let handle = assets.load(path.to_string()); + background_tasks.tasks.push(BackgroundTask::AssetLoading( + path.to_string(), + handle.clone().untyped(), + )); + load_server.scene = Some(handle); } EditorPrefabPath::MemoryCahce => { load_server.scene = cache.scene.clone(); diff --git a/src/editor/core/task_storage.rs b/src/editor/core/task_storage.rs new file mode 100644 index 00000000..0da23214 --- /dev/null +++ b/src/editor/core/task_storage.rs @@ -0,0 +1,43 @@ +use bevy::{prelude::*, asset::LoadState}; + +pub struct BackgroundTaskStoragePlugin; + +impl Plugin for BackgroundTaskStoragePlugin { + fn build(&self, app: &mut App) { + app.init_resource::(); + + app.add_systems(PostUpdate, update_storage); + } +} + +#[derive(Resource, Default)] +pub struct BackgroundTaskStorage { + pub tasks: Vec +} + +pub enum BackgroundTask { + AssetLoading(String, UntypedHandle), + None +} + +fn update_storage( + mut storage: ResMut, + assets : Res +) { + if storage.tasks.len() > 0 { + let mut need_remove_task = false; + match &storage.tasks[0] { + BackgroundTask::AssetLoading(path, handle) => { + let load_state = assets.get_load_state(handle.id()); + if load_state == Some(LoadState::Loaded) || load_state == None || load_state == Some(LoadState::Failed) { + need_remove_task = true; + } + } + BackgroundTask::None => {need_remove_task = true;} + } + + if need_remove_task { + storage.tasks.remove(0); + } + } +} \ No newline at end of file diff --git a/src/editor/ui/bot_menu.rs b/src/editor/ui/bot_menu.rs index b5eabdae..589a275e 100644 --- a/src/editor/ui/bot_menu.rs +++ b/src/editor/ui/bot_menu.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use bevy_egui::*; use crate::{ - editor::core::{EditorEvent, EditorPrefabPath}, + editor::core::{EditorEvent, EditorPrefabPath, BackgroundTaskStorage, BackgroundTask}, prefab::PrefabPlugin, EditorSet, EditorState, }; @@ -65,6 +65,7 @@ pub fn bot_menu( mut events: EventReader, mut menu_state: ResMut, mut editor_events: EventWriter, + background_tasks : Res ) { let ctx = ctxs.ctx_mut(); egui::TopBottomPanel::bottom("bot menu").show(ctx, |ui| { @@ -181,6 +182,20 @@ pub fn bot_menu( if ui.button("▶").clicked() { editor_events.send(EditorEvent::StartGame); } + + ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| { + if background_tasks.tasks.len() > 0 { + //Spinning circle + ui.spinner(); + + match &background_tasks.tasks[0] { + BackgroundTask::AssetLoading(path, _) => { + ui.label(format!("Loading {}", path)); + } + BackgroundTask::None => {} + } + } + }); }); }); From e50f3aa9ae8f722d18cc045cfffb616a4a8e143b Mon Sep 17 00:00:00 2001 From: rewin Date: Mon, 13 Nov 2023 09:03:40 +0300 Subject: [PATCH 20/35] Undo redo base --- src/editor/core/mod.rs | 3 ++ src/editor/core/undo.rs | 110 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 src/editor/core/undo.rs diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index 6bf88165..5f5ec9c9 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -10,6 +10,9 @@ pub use tool::*; pub mod task_storage; pub use task_storage::*; +pub mod undo; +pub use undo::*; + #[cfg(feature = "persistance_editor")] pub mod persistance; #[cfg(feature = "persistance_editor")] diff --git a/src/editor/core/undo.rs b/src/editor/core/undo.rs new file mode 100644 index 00000000..3cdb45e7 --- /dev/null +++ b/src/editor/core/undo.rs @@ -0,0 +1,110 @@ +use std::sync::Arc; + +use bevy::prelude::*; + +pub struct UndoPlugin; + +impl Plugin for UndoPlugin { + fn build(&self, app: &mut App) { + app.init_resource::(); + + app.add_event::(); + + app.add_systems( + Update, + (update_change_chain, undo_redo_logic) + ); + } +} + +fn update_change_chain( + mut change_chain: ResMut, + mut events: EventReader +) { + for event in events.read() { + change_chain.changes.push(event.change.clone()); + change_chain.changes_for_redo.clear(); + } +} + +fn undo_redo_logic( + world : &mut World +) { + world.resource_scope::, _>(|world, events| { + world.resource_scope::(|world, mut change_chain| { + let mut reader = events.get_reader(); + for event in reader.read(&events) { + match event { + UndoRedo::Undo => { + if let Some(change) = change_chain.changes.pop() { + change.revert(world).unwrap(); + change_chain.changes_for_redo.push(change); + } + }, + UndoRedo::Redo => { + if let Some(redo_change) = change_chain.changes_for_redo.pop() { + redo_change.apply(world).unwrap(); + change_chain.changes.push(redo_change); + } + }, + } + } + }); + }); +} + +#[derive(Resource, Default)] +pub struct ChangeChain { + pub changes: Vec>, + pub changes_for_redo : Vec>, +} + +pub trait EditorChange { + fn revert(&self, world : &mut World) -> Result<(), String>; + fn apply(&self, world : &mut World) -> Result<(), String>; +} + +#[derive(Event)] +pub enum UndoRedo { + Undo, + Redo +} + +#[derive(Event)] +pub struct NewChange { + pub change: Arc +} + +pub struct ComponentChange { + old_value: T, + new_value: T, + entity: Entity +} + +impl EditorChange for ComponentChange { + fn revert(&self, world : &mut World) -> Result<(), String> { + world.entity_mut(self.entity).insert(self.old_value.clone()); + Ok(()) + } + + fn apply(&self, world : &mut World) -> Result<(), String> { + world.entity_mut(self.entity).insert(self.new_value.clone()); + Ok(()) + } +} + +pub struct NewEntityChange { + entity: Entity +} + +impl EditorChange for NewEntityChange { + fn revert(&self, world : &mut World) -> Result<(), String> { + world.entity_mut(self.entity).despawn(); + Ok(()) + } + + fn apply(&self, world : &mut World) -> Result<(), String> { + // world.get_or_spawn(entity) + Ok(()) + } +} \ No newline at end of file From b9113e25c7159b21be444705595eb59e86a5aa18 Mon Sep 17 00:00:00 2001 From: "a.yamaev" Date: Wed, 22 Nov 2023 11:07:20 +0300 Subject: [PATCH 21/35] added undo plugin --- src/editor/core/mod.rs | 1 + src/editor/core/undo.rs | 182 ++++++++++++++++++++++++++++++--- src/editor/ui/inspector/mod.rs | 24 ++++- 3 files changed, 188 insertions(+), 19 deletions(-) diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index 5f5ec9c9..dce66f10 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -38,6 +38,7 @@ impl Plugin for EditorCore { app.add_plugins(PersistancePlugin); app.add_plugins(BackgroundTaskStoragePlugin); + app.add_plugins(UndoPlugin); app.add_event::(); diff --git a/src/editor/core/undo.rs b/src/editor/core/undo.rs index 3cdb45e7..0ec71801 100644 --- a/src/editor/core/undo.rs +++ b/src/editor/core/undo.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use bevy::prelude::*; +use bevy::{prelude::*, utils::HashMap, scene::DynamicEntity}; pub struct UndoPlugin; @@ -14,9 +14,12 @@ impl Plugin for UndoPlugin { Update, (update_change_chain, undo_redo_logic) ); + + app.auto_undo::(); } } + fn update_change_chain( mut change_chain: ResMut, mut events: EventReader @@ -37,13 +40,13 @@ fn undo_redo_logic( match event { UndoRedo::Undo => { if let Some(change) = change_chain.changes.pop() { - change.revert(world).unwrap(); + change.revert(world, &change_chain.entity_remap).unwrap(); change_chain.changes_for_redo.push(change); } }, UndoRedo::Redo => { if let Some(redo_change) = change_chain.changes_for_redo.pop() { - redo_change.apply(world).unwrap(); + redo_change.apply(world, &change_chain.entity_remap).unwrap(); change_chain.changes.push(redo_change); } }, @@ -57,11 +60,50 @@ fn undo_redo_logic( pub struct ChangeChain { pub changes: Vec>, pub changes_for_redo : Vec>, + entity_remap : HashMap, +} + +impl ChangeChain { + pub fn undo(&mut self, world : &mut World) { + if let Some(change) = self.changes.pop() { + let res = change.revert(world, &self.entity_remap).unwrap(); + self.changes_for_redo.push(change); + self.update_remap(res); + } + } + + pub fn redo(&mut self, world : &mut World) { + if let Some(change) = self.changes_for_redo.pop() { + let res = change.apply(world, &self.entity_remap).unwrap(); + self.changes.push(change); + self.update_remap(res); + } + } + + fn update_remap(&mut self, result : ChangeResult) { + match result { + ChangeResult::Success => {}, + ChangeResult::SuccessWithRemap(new_remap) => { + for (prev, new) in new_remap { + self.entity_remap.insert(prev, new); + } + }, + } + } +} + +pub fn get_entity_with_remap(entity : Entity, world : &World, entity_remap : &HashMap) -> Entity { + *entity_remap.get(&entity).unwrap_or(&entity) } pub trait EditorChange { - fn revert(&self, world : &mut World) -> Result<(), String>; - fn apply(&self, world : &mut World) -> Result<(), String>; + fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result; + fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result; +} + +pub enum ChangeResult { + Success, + SuccessWithRemap(Vec<(Entity, Entity)>), } #[derive(Event)] @@ -82,14 +124,14 @@ pub struct ComponentChange { } impl EditorChange for ComponentChange { - fn revert(&self, world : &mut World) -> Result<(), String> { - world.entity_mut(self.entity).insert(self.old_value.clone()); - Ok(()) + fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result { + world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).insert(self.old_value.clone()); + Ok(ChangeResult::Success) } - fn apply(&self, world : &mut World) -> Result<(), String> { - world.entity_mut(self.entity).insert(self.new_value.clone()); - Ok(()) + fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result { + world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).insert(self.new_value.clone()); + Ok(ChangeResult::Success) } } @@ -98,13 +140,119 @@ pub struct NewEntityChange { } impl EditorChange for NewEntityChange { - fn revert(&self, world : &mut World) -> Result<(), String> { - world.entity_mut(self.entity).despawn(); - Ok(()) + fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result { + world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).despawn(); + Ok(ChangeResult::Success) + } + + fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result { + let new_entity = world.spawn_empty().id(); + Ok(ChangeResult::SuccessWithRemap(vec![(self.entity, new_entity)])) + } +} + +pub struct RemoveEntityChange { + entity: Entity, + scene : DynamicScene +} + +impl EditorChange for RemoveEntityChange { + fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result { + let mut entity_map = HashMap::new(); + + self.scene.write_to_world(world, &mut entity_map).unwrap(); + let vec_changes = entity_map.into_iter().map(|(prev, new)| { + (prev, new) + }).collect::>(); + + Ok(ChangeResult::SuccessWithRemap(vec_changes)) + } + + fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result { + world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).despawn(); + Ok(ChangeResult::Success) + } +} + +#[derive(Component)] +pub struct ChangedMarker { + _phantom : std::marker::PhantomData +} + +impl Default for ChangedMarker { + fn default() -> Self { + Self { + _phantom : std::marker::PhantomData + } } +} + +#[derive(Resource)] +pub struct AutoUndoStorage { + pub storage : HashMap +} + +impl Default for AutoUndoStorage { + fn default() -> Self { + Self { + storage: HashMap::new() + } + } +} + +pub trait AppAutoUndo { + fn auto_undo(&mut self) -> &mut Self; +} + +impl AppAutoUndo for App { + fn auto_undo(&mut self) -> &mut Self { + + self.world.insert_resource(AutoUndoStorage::::default()); + + self.add_systems( + PostUpdate, + ( + auto_undo_system_changed::, + auto_undo_system::, + ).chain() + ); + + self + } +} + +fn auto_undo_system_changed( + mut commands : Commands, + mut storage : ResMut>, + query : Query>) { + for entity in query.iter() { + commands.entity(entity).insert(ChangedMarker::::default()); + } +} + +fn auto_undo_system( + mut commands : Commands, + mut storage : ResMut>, + mut query : Query<(Entity, &mut T), With>>, + mut new_change : EventWriter) { + for (e, data) in query.iter_mut() { + if !data.is_changed() { + commands.entity(e).remove::>(); + + if let Some(prev_value) = storage.storage.get(&e) { + new_change.send(NewChange { + change : Arc::new(ComponentChange { + old_value: prev_value.clone(), + new_value: data.clone(), + entity: e, + }) + }); + info!("Auto undo change for entity {:?}", e); + } else { + + } - fn apply(&self, world : &mut World) -> Result<(), String> { - // world.get_or_spawn(entity) - Ok(()) + storage.storage.insert(e, data.clone()); + } } } \ No newline at end of file diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index 902413da..d649855d 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -6,7 +6,7 @@ use bevy::{ ecs::{change_detection::MutUntyped, system::CommandQueue, component::ComponentId}, prelude::*, ptr::PtrMut, - reflect::ReflectFromPtr, utils::HashMap, + reflect::{ReflectFromPtr, DynamicStruct}, utils::HashMap, scene::DynamicEntity, }; use bevy_egui::*; @@ -48,7 +48,8 @@ impl Plugin for SpaceInspectorPlugin { #[derive(Resource, Default)] pub struct InspectorTab { - default_opened : HashMap + default_opened : HashMap, + undo_cache : HashMap } impl EditorTab for InspectorTab { @@ -164,6 +165,25 @@ pub fn inspect(tab : &mut InspectorTab, ui: &mut egui::Ui, world: &mut World) { egui::ScrollArea::vertical().show(ui, |ui| { for e in selected.iter() { if let Some(e) = cell.get_entity(*e) { + + let cache = if let Some(cache) = tab.undo_cache.get_mut(&e.id()) { + cache + } else { + let mut dyn_e = DynamicEntity { + entity: e.id(), + components: vec![], + }; + for c in e.archetype().components() { + if let Some(mut component) = e.get_mut_by_id(c) { + let type_id = cell.components().get_info(c).unwrap().type_id().unwrap(); + let reflected = registry.get(type_id).unwrap().data::().unwrap().from_ptr_mut()(component.as_mut()); + dyn_e.components.push(reflected.clone_value()); + } + } + tab.undo_cache.insert(e.id(), dyn_e); + tab.undo_cache.get_mut(&e.id()).unwrap() + }; + let mut name; if let Some(name_struct) = e.get::() { name = name_struct.as_str().to_string(); From 4a9e08cb168e5e96f484076a69fac066063612fe Mon Sep 17 00:00:00 2001 From: "a.yamaev" Date: Thu, 23 Nov 2023 13:21:37 +0300 Subject: [PATCH 22/35] First worked undo redo for transforms --- src/editor/core/undo.rs | 110 ++++++++++++++++++++++++++------- src/editor/ui/change_chain.rs | 38 ++++++++++++ src/editor/ui/game_view.rs | 12 +++- src/editor/ui/inspector/mod.rs | 34 +++++----- src/editor/ui/mod.rs | 6 +- 5 files changed, 158 insertions(+), 42 deletions(-) create mode 100644 src/editor/ui/change_chain.rs diff --git a/src/editor/core/undo.rs b/src/editor/core/undo.rs index 0ec71801..625792c0 100644 --- a/src/editor/core/undo.rs +++ b/src/editor/core/undo.rs @@ -1,6 +1,8 @@ -use std::sync::Arc; +use std::{sync::Arc, fmt::format}; -use bevy::{prelude::*, utils::HashMap, scene::DynamicEntity}; +use bevy::{prelude::*, utils::{HashMap, HashSet}}; + +use crate::PrefabMarker; pub struct UndoPlugin; @@ -9,16 +11,29 @@ impl Plugin for UndoPlugin { app.init_resource::(); app.add_event::(); + app.add_event::(); app.add_systems( - Update, - (update_change_chain, undo_redo_logic) + PostUpdate, + (clear_one_frame_ignore, update_change_chain, undo_redo_logic).chain() ); app.auto_undo::(); } } +#[derive(Component)] +pub struct OneFrameUndoIgnore { + pub counter : i32 +} + +impl Default for OneFrameUndoIgnore { + fn default() -> Self { + Self { + counter : 3 + } + } +} fn update_change_chain( mut change_chain: ResMut, @@ -30,28 +45,43 @@ fn update_change_chain( } } +fn clear_one_frame_ignore( + mut commands : Commands, + mut query : Query<(Entity, &mut OneFrameUndoIgnore)> +) { + for (e, mut ignore) in query.iter_mut() { + ignore.counter -= 1; + if ignore.counter <= 0 { + commands.entity(e).remove::(); + } + } +} + fn undo_redo_logic( world : &mut World ) { - world.resource_scope::, _>(|world, events| { + world.resource_scope::, _>(|world, mut events| { world.resource_scope::(|world, mut change_chain| { - let mut reader = events.get_reader(); - for event in reader.read(&events) { - match event { - UndoRedo::Undo => { - if let Some(change) = change_chain.changes.pop() { - change.revert(world, &change_chain.entity_remap).unwrap(); - change_chain.changes_for_redo.push(change); - } - }, - UndoRedo::Redo => { - if let Some(redo_change) = change_chain.changes_for_redo.pop() { - redo_change.apply(world, &change_chain.entity_remap).unwrap(); - change_chain.changes.push(redo_change); - } - }, + { + let mut reader = events.get_reader(); + for event in reader.read(&events) { + match event { + UndoRedo::Undo => { + if let Some(change) = change_chain.changes.pop() { + change.revert(world, &change_chain.entity_remap).unwrap(); + change_chain.changes_for_redo.push(change); + } + }, + UndoRedo::Redo => { + if let Some(redo_change) = change_chain.changes_for_redo.pop() { + redo_change.apply(world, &change_chain.entity_remap).unwrap(); + change_chain.changes.push(redo_change); + } + }, + } } } + events.clear(); }); }); } @@ -99,6 +129,7 @@ pub fn get_entity_with_remap(entity : Entity, world : &World, entity_remap : &Ha pub trait EditorChange { fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result; fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result; + fn debug_text(&self) -> String; } pub enum ChangeResult { @@ -125,14 +156,19 @@ pub struct ComponentChange { impl EditorChange for ComponentChange { fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result { - world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).insert(self.old_value.clone()); + let e = get_entity_with_remap(self.entity, world, entity_remap); + world.entity_mut(e).insert(self.old_value.clone()).insert(OneFrameUndoIgnore::default()); Ok(ChangeResult::Success) } fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result { - world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).insert(self.new_value.clone()); + world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).insert(self.new_value.clone()).insert(OneFrameUndoIgnore::default()); Ok(ChangeResult::Success) } + + fn debug_text(&self) -> String { + format!("ComponentChange for entity {:?}", self.entity) + } } pub struct NewEntityChange { @@ -149,6 +185,10 @@ impl EditorChange for NewEntityChange { let new_entity = world.spawn_empty().id(); Ok(ChangeResult::SuccessWithRemap(vec![(self.entity, new_entity)])) } + + fn debug_text(&self) -> String { + format!("NewEntityChange for entity {:?}", self.entity) + } } pub struct RemoveEntityChange { @@ -172,6 +212,10 @@ impl EditorChange for RemoveEntityChange { world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).despawn(); Ok(ChangeResult::Success) } + + fn debug_text(&self) -> String { + format!("RemoveEntityChange for entity {:?}", self.entity) + } } #[derive(Component)] @@ -212,6 +256,8 @@ impl AppAutoUndo for App { self.add_systems( PostUpdate, ( + auto_undo_update_cache::, + auto_undo_add_init::, auto_undo_system_changed::, auto_undo_system::, ).chain() @@ -221,10 +267,28 @@ impl AppAutoUndo for App { } } +fn auto_undo_update_cache( + mut storage : ResMut>, + ignored_query : Query<(Entity, &T), With> +) { + for (e, data) in ignored_query.iter() { + storage.storage.insert(e, data.clone()); + } +} + +fn auto_undo_add_init( + mut storage : ResMut>, + query : Query<(Entity, &T), (With, Added, Without)> +) { + for (e, data) in query.iter() { + storage.storage.insert(e, data.clone()); + } +} + fn auto_undo_system_changed( mut commands : Commands, mut storage : ResMut>, - query : Query>) { + query : Query, Changed, Without)>) { for entity in query.iter() { commands.entity(entity).insert(ChangedMarker::::default()); } diff --git a/src/editor/ui/change_chain.rs b/src/editor/ui/change_chain.rs new file mode 100644 index 00000000..850b1ce0 --- /dev/null +++ b/src/editor/ui/change_chain.rs @@ -0,0 +1,38 @@ +use bevy::prelude::*; + +use crate::editor::core::ChangeChain; +use super::{editor_tab::EditorTab, EditorUiAppExt}; + +pub struct ChangeChainViewPlugin; + +impl Plugin for ChangeChainViewPlugin { + fn build(&self, app: &mut App) { + app.editor_tab_by_trait(super::editor_tab::EditorTabName::Other("Change Chain".to_string()), ChangeChainView::default()); + } +} + +#[derive(Resource)] +pub struct ChangeChainView { + +} + +impl Default for ChangeChainView { + fn default() -> Self { + Self { + } + } +} + +impl EditorTab for ChangeChainView { + fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands: &mut bevy::prelude::Commands, world: &mut bevy::prelude::World) { + let change_chain = world.resource::(); + + for change in change_chain.changes.iter() { + ui.label(change.debug_text()); + } + } + + fn title(&self) -> bevy_egui::egui::WidgetText { + "Change Chain".into() + } +} \ No newline at end of file diff --git a/src/editor/ui/game_view.rs b/src/editor/ui/game_view.rs index bd8cc4e9..2e55375f 100644 --- a/src/editor/ui/game_view.rs +++ b/src/editor/ui/game_view.rs @@ -2,7 +2,7 @@ use bevy::{prelude::*, window::PrimaryWindow}; use bevy_egui::egui::{self}; use egui_gizmo::GizmoMode; -use crate::{editor::core::EditorTool, prelude::EditorTab, EditorCameraMarker}; +use crate::{editor::core::{EditorTool, UndoRedo}, prelude::EditorTab, EditorCameraMarker}; #[derive(Resource)] pub struct GameViewTab { @@ -27,6 +27,16 @@ impl Default for GameViewTab { impl EditorTab for GameViewTab { fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands: &mut Commands, world: &mut World) { + + if ui.input_mut(|i| i.key_released(egui::Key::Z) && i.modifiers.ctrl && !i.modifiers.shift) { + world.send_event(UndoRedo::Undo); + info!("Undo command"); + } + if ui.input_mut(|i| i.key_released(egui::Key::Z) && i.modifiers.ctrl && i.modifiers.shift) { + world.send_event(UndoRedo::Redo); + info!("Redo command"); + } + self.viewport_rect = Some(ui.clip_rect()); //Draw FPS diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index d649855d..e67e06ae 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -166,23 +166,23 @@ pub fn inspect(tab : &mut InspectorTab, ui: &mut egui::Ui, world: &mut World) { for e in selected.iter() { if let Some(e) = cell.get_entity(*e) { - let cache = if let Some(cache) = tab.undo_cache.get_mut(&e.id()) { - cache - } else { - let mut dyn_e = DynamicEntity { - entity: e.id(), - components: vec![], - }; - for c in e.archetype().components() { - if let Some(mut component) = e.get_mut_by_id(c) { - let type_id = cell.components().get_info(c).unwrap().type_id().unwrap(); - let reflected = registry.get(type_id).unwrap().data::().unwrap().from_ptr_mut()(component.as_mut()); - dyn_e.components.push(reflected.clone_value()); - } - } - tab.undo_cache.insert(e.id(), dyn_e); - tab.undo_cache.get_mut(&e.id()).unwrap() - }; + // let cache = if let Some(cache) = tab.undo_cache.get_mut(&e.id()) { + // cache + // } else { + // let mut dyn_e = DynamicEntity { + // entity: e.id(), + // components: vec![], + // }; + // for c in e.archetype().components() { + // if let Some(mut component) = e.get_mut_by_id(c) { + // let type_id = cell.components().get_info(c).unwrap().type_id().unwrap(); + // let reflected = registry.get(type_id).unwrap().data::().unwrap().from_ptr_mut()(component.as_mut()); + // dyn_e.components.push(reflected.clone_value()); + // } + // } + // tab.undo_cache.insert(e.id(), dyn_e); + // tab.undo_cache.get_mut(&e.id()).unwrap() + // }; let mut name; if let Some(name_struct) = e.get::() { diff --git a/src/editor/ui/mod.rs b/src/editor/ui/mod.rs index 851f111d..adf66df3 100644 --- a/src/editor/ui/mod.rs +++ b/src/editor/ui/mod.rs @@ -25,6 +25,9 @@ pub use settings::*; pub mod tools; pub use tools::*; +pub mod change_chain; +pub use change_chain::*; + pub mod debug_panels; use bevy::{ecs::system::CommandQueue, prelude::*, utils::HashMap, window::PrimaryWindow}; @@ -35,7 +38,7 @@ use crate::{EditorSet, EditorState}; use self::tools::gizmo::GizmoTool; use super::{ - core::{SelectedPlugin, ToolExt}, + core::{SelectedPlugin, ToolExt, UndoRedo}, update_pan_orbit, }; @@ -99,6 +102,7 @@ impl Plugin for EditorUiPlugin { app.world.resource_mut::().active_tool = Some(0); app.add_plugins(settings::SettingsWindowPlugin); + app.add_plugins(ChangeChainViewPlugin); if self.use_standard_layout { let mut editor = app.world.resource_mut::(); From ada75a7dc36280053777cd08ae8c12f11b0c46ac Mon Sep 17 00:00:00 2001 From: "a.yamaev" Date: Thu, 23 Nov 2023 13:34:19 +0300 Subject: [PATCH 23/35] Merge branches --- src/editor/core/gltf_unpack.rs | 4 +- src/editor/core/mod.rs | 3 +- src/editor/core/persistance.rs | 171 +++++++++++++++---------- src/editor/core/task_storage.rs | 22 ++-- src/editor/core/undo.rs | 215 ++++++++++++++++++++------------ src/editor/mod.rs | 7 -- src/editor/ui/bot_menu.rs | 4 +- src/editor/ui/change_chain.rs | 23 ++-- src/editor/ui/game_view.rs | 10 +- src/editor/ui/inspector/mod.rs | 23 +--- src/editor/ui/mod.rs | 52 ++++---- src/editor/ui/settings.rs | 3 +- 12 files changed, 307 insertions(+), 230 deletions(-) diff --git a/src/editor/core/gltf_unpack.rs b/src/editor/core/gltf_unpack.rs index 4ba6ae2b..fb7a86f6 100644 --- a/src/editor/core/gltf_unpack.rs +++ b/src/editor/core/gltf_unpack.rs @@ -11,7 +11,7 @@ use crate::{ PrefabMarker, }; -use super::{BackgroundTaskStorage, BackgroundTask}; +use super::{BackgroundTask, BackgroundTaskStorage}; #[derive(Event)] pub struct EditorUnpackGltf { @@ -49,7 +49,7 @@ fn unpack_gltf_event( mut events: EventReader, assets: Res, mut queue: ResMut, - mut background_tasks : ResMut, + mut background_tasks: ResMut, ) { for event in events.read() { let handle = assets.load(event.path.clone()); diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index 3c0fe49a..11981e13 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -19,7 +19,6 @@ pub mod persistance; pub use persistance::*; pub mod gltf_unpack; -pub mod settings; use bevy::prelude::*; @@ -84,7 +83,7 @@ fn editor_event_listener( mut start_game_state: ResMut>, cache: ResMut, mut gltf_events: EventWriter, - mut background_tasks : ResMut, + mut background_tasks: ResMut, ) { for event in events.read() { match event { diff --git a/src/editor/core/persistance.rs b/src/editor/core/persistance.rs index 3992fea1..9b7d36a4 100644 --- a/src/editor/core/persistance.rs +++ b/src/editor/core/persistance.rs @@ -2,8 +2,16 @@ use std::any::TypeId; -use bevy::{prelude::*, utils::HashMap, reflect::{TypeRegistry, serde::{ReflectSerializer, TypedReflectDeserializer, UntypedReflectDeserializer}, GetTypeRegistration}, window::WindowCloseRequested}; -use ron::{*, ser::PrettyConfig}; +use bevy::{ + prelude::*, + reflect::{ + serde::{ReflectSerializer, TypedReflectDeserializer, UntypedReflectDeserializer}, + GetTypeRegistration, TypeRegistry, + }, + utils::HashMap, + window::WindowCloseRequested, +}; +use ron::{ser::PrettyConfig, *}; use serde::de::DeserializeSeed; pub struct PersistancePlugin; @@ -12,28 +20,34 @@ pub struct PersistancePlugin; pub enum PersistanceSet { EventReader, ResourceProcess, - Collect + Collect, } impl Plugin for PersistancePlugin { fn build(&self, app: &mut App) { - app - .init_resource::() + app.init_resource::() .init_resource::(); app.add_event::(); app.add_event::(); - app.configure_sets(Update, ( - PersistanceSet::EventReader, - PersistanceSet::ResourceProcess, - PersistanceSet::Collect - ).chain()); + app.configure_sets( + Update, + ( + PersistanceSet::EventReader, + PersistanceSet::ResourceProcess, + PersistanceSet::Collect, + ) + .chain(), + ); app.add_systems(Startup, persistance_startup_load); app.add_systems(PreUpdate, persistance_save_on_close); - app.add_systems(Update, persistance_start.in_set(PersistanceSet::EventReader)); + app.add_systems( + Update, + persistance_start.in_set(PersistanceSet::EventReader), + ); app.add_systems(Update, persistance_end.in_set(PersistanceSet::Collect)); app.persistance_resource::(); @@ -42,8 +56,8 @@ impl Plugin for PersistancePlugin { fn persistance_save_on_close( mut events: EventWriter, - settings : Res, - mut close_events : EventReader, + settings: Res, + mut close_events: EventReader, ) { if settings.save_on_close { if close_events.read().next().is_some() { @@ -54,19 +68,17 @@ fn persistance_save_on_close( fn persistance_startup_load( mut events: EventWriter, - settings : Res, + settings: Res, ) { if settings.load_on_startup { events.send(PersistanceEvent::Load); } } - - fn persistance_start( mut events: EventReader, - mut broadcast : EventWriter, - mut persistance : ResMut, + mut broadcast: EventWriter, + mut persistance: ResMut, ) { for event in events.read() { match event { @@ -74,7 +86,7 @@ fn persistance_start( broadcast.send(PersistanceResourceBroadcastEvent::Pack); persistance.mode = PersistanceMode::Saving; persistance.save_counter = 0; - }, + } PersistanceEvent::Load => { match &persistance.source { PersistanceDataSource::File(path) => { @@ -84,58 +96,61 @@ fn persistance_start( }; let data: HashMap = ron::de::from_reader(file).unwrap(); persistance.data = data; - }, + } PersistanceDataSource::Memory => { //do nothing - }, + } } broadcast.send(PersistanceResourceBroadcastEvent::Unpack); persistance.mode = PersistanceMode::Loading; persistance.load_counter = 0; - }, + } } } } -fn persistance_end( - mut persistance : ResMut, -) { +fn persistance_end(mut persistance: ResMut) { let mode = persistance.mode.clone(); match mode { PersistanceMode::Saving => { persistance.mode = PersistanceMode::None; if persistance.save_counter != persistance.target_count { - error!("Persistance saving error: {} of {} resources were saved", persistance.save_counter, persistance.target_count); + error!( + "Persistance saving error: {} of {} resources were saved", + persistance.save_counter, persistance.target_count + ); } match &persistance.source { PersistanceDataSource::File(path) => { let mut file = std::fs::File::create(path).unwrap(); ron::ser::to_writer_pretty( - &mut file, - &persistance.data, - PrettyConfig::default()).unwrap(); - }, + &mut file, + &persistance.data, + PrettyConfig::default(), + ) + .unwrap(); + } PersistanceDataSource::Memory => { //do nothing - }, - } { - + } } - }, + {} + } PersistanceMode::Loading => { persistance.mode = PersistanceMode::None; if persistance.load_counter == persistance.target_count { - error!("Persistance loading error: {} of {} resources were loaded", persistance.load_counter, persistance.target_count); + error!( + "Persistance loading error: {} of {} resources were loaded", + persistance.load_counter, persistance.target_count + ); } - }, + } _ => {} - } } - #[derive(Resource, Reflect)] #[reflect(Resource)] pub struct PersistanceSettings { @@ -154,26 +169,26 @@ impl Default for PersistanceSettings { #[derive(Default, Clone)] enum PersistanceMode { - Saving, + Saving, Loading, #[default] - None + None, } /// ['PersistanceRegistry'] contains lambda functions for loading/unloading editor state -/// At the moment of closing the window or starting the game mode, -/// all necessary data is saved to a file/memory, and then restored when the editor mode is opened. +/// At the moment of closing the window or starting the game mode, +/// all necessary data is saved to a file/memory, and then restored when the editor mode is opened. /// When the restored resource is loaded, the ['PersistenceLoaded'] event is generated -/// +/// /// ['PersistenceLoaded']: crate::editor::core::persistance::PersistanceLoaded #[derive(Resource, Default)] pub struct PersistanceRegistry { - source : PersistanceDataSource, + source: PersistanceDataSource, data: HashMap, load_counter: usize, save_counter: usize, target_count: usize, - mode: PersistanceMode + mode: PersistanceMode, } #[derive(Event, Default)] @@ -187,7 +202,6 @@ pub enum PersistanceEvent { Load, } - #[derive(Event)] enum PersistanceResourceBroadcastEvent { Unpack, @@ -198,7 +212,7 @@ enum PersistanceResourceBroadcastEvent { #[reflect(Default)] pub enum PersistanceDataSource { File(String), - Memory + Memory, } impl Default for PersistanceDataSource { @@ -207,31 +221,40 @@ impl Default for PersistanceDataSource { } } - pub trait AppPersistanceExt { - fn persistance_resource(&mut self) -> &mut Self; + fn persistance_resource( + &mut self, + ) -> &mut Self; } impl AppPersistanceExt for App { - fn persistance_resource(&mut self) -> &mut Self { - self.world.resource_mut::().target_count += 1; + fn persistance_resource( + &mut self, + ) -> &mut Self { + self.world + .resource_mut::() + .target_count += 1; self.register_type::(); self.add_event::>(); - self.add_systems(Update, persistance_resource_system::.in_set(PersistanceSet::ResourceProcess)); + self.add_systems( + Update, + persistance_resource_system::.in_set(PersistanceSet::ResourceProcess), + ); self } } - -fn persistance_resource_system( +fn persistance_resource_system< + T: Default + Reflect + FromReflect + Resource + GetTypeRegistration, +>( mut events: EventReader, - mut persistance : ResMut, - mut resource : ResMut, - registry : Res, - mut persistance_loaded : EventWriter>, + mut persistance: ResMut, + mut resource: ResMut, + registry: Res, + mut persistance_loaded: EventWriter>, ) { for event in events.read() { match event { @@ -239,27 +262,39 @@ fn persistance_resource_system { - let Some(data) = persistance.data.get(T::get_type_registration().type_info().type_path()) else { - warn!("Persistance resource {} not found", T::get_type_registration().type_info().type_path()); + let Some(data) = persistance + .data + .get(T::get_type_registration().type_info().type_path()) + else { + warn!( + "Persistance resource {} not found", + T::get_type_registration().type_info().type_path() + ); continue; }; let type_registry = registry.read(); let deserializer = UntypedReflectDeserializer::new(&type_registry); - let reflected_value = deserializer.deserialize( - &mut ron::Deserializer::from_str(data).unwrap() - ).unwrap(); + let reflected_value = deserializer + .deserialize(&mut ron::Deserializer::from_str(data).unwrap()) + .unwrap(); let converted = ::from_reflect(&*reflected_value).unwrap(); *resource = converted; resource.set_changed(); - + persistance_loaded.send(PersistanceLoaded::::default()); persistance.load_counter += 1; - }, + } } } -} \ No newline at end of file +} diff --git a/src/editor/core/task_storage.rs b/src/editor/core/task_storage.rs index 0da23214..e487077d 100644 --- a/src/editor/core/task_storage.rs +++ b/src/editor/core/task_storage.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, asset::LoadState}; +use bevy::{asset::LoadState, prelude::*}; pub struct BackgroundTaskStoragePlugin; @@ -12,32 +12,34 @@ impl Plugin for BackgroundTaskStoragePlugin { #[derive(Resource, Default)] pub struct BackgroundTaskStorage { - pub tasks: Vec + pub tasks: Vec, } pub enum BackgroundTask { AssetLoading(String, UntypedHandle), - None + None, } -fn update_storage( - mut storage: ResMut, - assets : Res -) { +fn update_storage(mut storage: ResMut, assets: Res) { if storage.tasks.len() > 0 { let mut need_remove_task = false; match &storage.tasks[0] { BackgroundTask::AssetLoading(path, handle) => { let load_state = assets.get_load_state(handle.id()); - if load_state == Some(LoadState::Loaded) || load_state == None || load_state == Some(LoadState::Failed) { + if load_state == Some(LoadState::Loaded) + || load_state == None + || load_state == Some(LoadState::Failed) + { need_remove_task = true; } } - BackgroundTask::None => {need_remove_task = true;} + BackgroundTask::None => { + need_remove_task = true; + } } if need_remove_task { storage.tasks.remove(0); } } -} \ No newline at end of file +} diff --git a/src/editor/core/undo.rs b/src/editor/core/undo.rs index 625792c0..feca0ff0 100644 --- a/src/editor/core/undo.rs +++ b/src/editor/core/undo.rs @@ -1,6 +1,9 @@ -use std::{sync::Arc, fmt::format}; +use std::{fmt::format, sync::Arc}; -use bevy::{prelude::*, utils::{HashMap, HashSet}}; +use bevy::{ + prelude::*, + utils::{HashMap, HashSet}, +}; use crate::PrefabMarker; @@ -15,7 +18,7 @@ impl Plugin for UndoPlugin { app.add_systems( PostUpdate, - (clear_one_frame_ignore, update_change_chain, undo_redo_logic).chain() + (clear_one_frame_ignore, update_change_chain, undo_redo_logic).chain(), ); app.auto_undo::(); @@ -24,21 +27,16 @@ impl Plugin for UndoPlugin { #[derive(Component)] pub struct OneFrameUndoIgnore { - pub counter : i32 + pub counter: i32, } impl Default for OneFrameUndoIgnore { fn default() -> Self { - Self { - counter : 3 - } + Self { counter: 3 } } } -fn update_change_chain( - mut change_chain: ResMut, - mut events: EventReader -) { +fn update_change_chain(mut change_chain: ResMut, mut events: EventReader) { for event in events.read() { change_chain.changes.push(event.change.clone()); change_chain.changes_for_redo.clear(); @@ -46,8 +44,8 @@ fn update_change_chain( } fn clear_one_frame_ignore( - mut commands : Commands, - mut query : Query<(Entity, &mut OneFrameUndoIgnore)> + mut commands: Commands, + mut query: Query<(Entity, &mut OneFrameUndoIgnore)>, ) { for (e, mut ignore) in query.iter_mut() { ignore.counter -= 1; @@ -57,9 +55,7 @@ fn clear_one_frame_ignore( } } -fn undo_redo_logic( - world : &mut World -) { +fn undo_redo_logic(world: &mut World) { world.resource_scope::, _>(|world, mut events| { world.resource_scope::(|world, mut change_chain| { { @@ -71,13 +67,15 @@ fn undo_redo_logic( change.revert(world, &change_chain.entity_remap).unwrap(); change_chain.changes_for_redo.push(change); } - }, + } UndoRedo::Redo => { if let Some(redo_change) = change_chain.changes_for_redo.pop() { - redo_change.apply(world, &change_chain.entity_remap).unwrap(); + redo_change + .apply(world, &change_chain.entity_remap) + .unwrap(); change_chain.changes.push(redo_change); } - }, + } } } } @@ -89,12 +87,12 @@ fn undo_redo_logic( #[derive(Resource, Default)] pub struct ChangeChain { pub changes: Vec>, - pub changes_for_redo : Vec>, - entity_remap : HashMap, + pub changes_for_redo: Vec>, + entity_remap: HashMap, } impl ChangeChain { - pub fn undo(&mut self, world : &mut World) { + pub fn undo(&mut self, world: &mut World) { if let Some(change) = self.changes.pop() { let res = change.revert(world, &self.entity_remap).unwrap(); self.changes_for_redo.push(change); @@ -102,7 +100,7 @@ impl ChangeChain { } } - pub fn redo(&mut self, world : &mut World) { + pub fn redo(&mut self, world: &mut World) { if let Some(change) = self.changes_for_redo.pop() { let res = change.apply(world, &self.entity_remap).unwrap(); self.changes.push(change); @@ -110,25 +108,37 @@ impl ChangeChain { } } - fn update_remap(&mut self, result : ChangeResult) { + fn update_remap(&mut self, result: ChangeResult) { match result { - ChangeResult::Success => {}, + ChangeResult::Success => {} ChangeResult::SuccessWithRemap(new_remap) => { for (prev, new) in new_remap { self.entity_remap.insert(prev, new); } - }, + } } } } -pub fn get_entity_with_remap(entity : Entity, world : &World, entity_remap : &HashMap) -> Entity { +pub fn get_entity_with_remap( + entity: Entity, + world: &World, + entity_remap: &HashMap, +) -> Entity { *entity_remap.get(&entity).unwrap_or(&entity) } pub trait EditorChange { - fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result; - fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result; + fn revert( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result; + fn apply( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result; fn debug_text(&self) -> String; } @@ -140,50 +150,77 @@ pub enum ChangeResult { #[derive(Event)] pub enum UndoRedo { Undo, - Redo + Redo, } #[derive(Event)] pub struct NewChange { - pub change: Arc + pub change: Arc, } -pub struct ComponentChange { +pub struct ComponentChange { old_value: T, new_value: T, - entity: Entity + entity: Entity, } -impl EditorChange for ComponentChange { - fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result { +impl EditorChange for ComponentChange { + fn revert( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result { let e = get_entity_with_remap(self.entity, world, entity_remap); - world.entity_mut(e).insert(self.old_value.clone()).insert(OneFrameUndoIgnore::default()); + world + .entity_mut(e) + .insert(self.old_value.clone()) + .insert(OneFrameUndoIgnore::default()); Ok(ChangeResult::Success) } - fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result { - world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).insert(self.new_value.clone()).insert(OneFrameUndoIgnore::default()); + fn apply( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result { + world + .entity_mut(get_entity_with_remap(self.entity, world, entity_remap)) + .insert(self.new_value.clone()) + .insert(OneFrameUndoIgnore::default()); Ok(ChangeResult::Success) } fn debug_text(&self) -> String { format!("ComponentChange for entity {:?}", self.entity) } -} +} pub struct NewEntityChange { - entity: Entity + entity: Entity, } impl EditorChange for NewEntityChange { - fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result { - world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).despawn(); + fn revert( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result { + world + .entity_mut(get_entity_with_remap(self.entity, world, entity_remap)) + .despawn(); Ok(ChangeResult::Success) } - fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result { + fn apply( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result { let new_entity = world.spawn_empty().id(); - Ok(ChangeResult::SuccessWithRemap(vec![(self.entity, new_entity)])) + Ok(ChangeResult::SuccessWithRemap(vec![( + self.entity, + new_entity, + )])) } fn debug_text(&self) -> String { @@ -193,23 +230,34 @@ impl EditorChange for NewEntityChange { pub struct RemoveEntityChange { entity: Entity, - scene : DynamicScene + scene: DynamicScene, } impl EditorChange for RemoveEntityChange { - fn revert(&self, world : &mut World, entity_remap : &HashMap) -> Result { + fn revert( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result { let mut entity_map = HashMap::new(); - + self.scene.write_to_world(world, &mut entity_map).unwrap(); - let vec_changes = entity_map.into_iter().map(|(prev, new)| { - (prev, new) - }).collect::>(); + let vec_changes = entity_map + .into_iter() + .map(|(prev, new)| (prev, new)) + .collect::>(); Ok(ChangeResult::SuccessWithRemap(vec_changes)) } - fn apply(&self, world : &mut World, entity_remap : &HashMap) -> Result { - world.entity_mut(get_entity_with_remap(self.entity, world, entity_remap)).despawn(); + fn apply( + &self, + world: &mut World, + entity_remap: &HashMap, + ) -> Result { + world + .entity_mut(get_entity_with_remap(self.entity, world, entity_remap)) + .despawn(); Ok(ChangeResult::Success) } @@ -220,37 +268,36 @@ impl EditorChange for RemoveEntityChange { #[derive(Component)] pub struct ChangedMarker { - _phantom : std::marker::PhantomData + _phantom: std::marker::PhantomData, } impl Default for ChangedMarker { fn default() -> Self { Self { - _phantom : std::marker::PhantomData + _phantom: std::marker::PhantomData, } } } #[derive(Resource)] -pub struct AutoUndoStorage { - pub storage : HashMap +pub struct AutoUndoStorage { + pub storage: HashMap, } -impl Default for AutoUndoStorage { +impl Default for AutoUndoStorage { fn default() -> Self { Self { - storage: HashMap::new() + storage: HashMap::new(), } } } pub trait AppAutoUndo { - fn auto_undo(&mut self) -> &mut Self; + fn auto_undo(&mut self) -> &mut Self; } impl AppAutoUndo for App { - fn auto_undo(&mut self) -> &mut Self { - + fn auto_undo(&mut self) -> &mut Self { self.world.insert_resource(AutoUndoStorage::::default()); self.add_systems( @@ -260,63 +307,67 @@ impl AppAutoUndo for App { auto_undo_add_init::, auto_undo_system_changed::, auto_undo_system::, - ).chain() + ) + .chain(), ); self } } -fn auto_undo_update_cache( - mut storage : ResMut>, - ignored_query : Query<(Entity, &T), With> +fn auto_undo_update_cache( + mut storage: ResMut>, + ignored_query: Query<(Entity, &T), With>, ) { for (e, data) in ignored_query.iter() { storage.storage.insert(e, data.clone()); } } -fn auto_undo_add_init( - mut storage : ResMut>, - query : Query<(Entity, &T), (With, Added, Without)> +fn auto_undo_add_init( + mut storage: ResMut>, + query: Query<(Entity, &T), (With, Added, Without)>, ) { for (e, data) in query.iter() { storage.storage.insert(e, data.clone()); } } -fn auto_undo_system_changed( - mut commands : Commands, - mut storage : ResMut>, - query : Query, Changed, Without)>) { +fn auto_undo_system_changed( + mut commands: Commands, + mut storage: ResMut>, + query: Query, Changed, Without)>, +) { for entity in query.iter() { - commands.entity(entity).insert(ChangedMarker::::default()); + commands + .entity(entity) + .insert(ChangedMarker::::default()); } } -fn auto_undo_system( - mut commands : Commands, - mut storage : ResMut>, - mut query : Query<(Entity, &mut T), With>>, - mut new_change : EventWriter) { +fn auto_undo_system( + mut commands: Commands, + mut storage: ResMut>, + mut query: Query<(Entity, &mut T), With>>, + mut new_change: EventWriter, +) { for (e, data) in query.iter_mut() { if !data.is_changed() { commands.entity(e).remove::>(); if let Some(prev_value) = storage.storage.get(&e) { new_change.send(NewChange { - change : Arc::new(ComponentChange { + change: Arc::new(ComponentChange { old_value: prev_value.clone(), new_value: data.clone(), entity: e, - }) + }), }); info!("Auto undo change for entity {:?}", e); } else { - } storage.storage.insert(e, data.clone()); } } -} \ No newline at end of file +} diff --git a/src/editor/mod.rs b/src/editor/mod.rs index c72f952c..a6e7a089 100644 --- a/src/editor/mod.rs +++ b/src/editor/mod.rs @@ -43,7 +43,6 @@ impl Plugin for EditorPlugin { } app.add_plugins(core::EditorCore); - #[cfg(feature = "bevy_xpbd_3d")] { app.add_plugins(crate::optional::bevy_xpbd_plugin::BevyXpbdEditorPlugin); @@ -136,12 +135,6 @@ impl Plugin for EditorPlugin { .run_if(input_toggle_active(false, KeyCode::Escape)), ); - - #[cfg(feature = "bevy_xpbd_3d")] - { - app.add_plugins(crate::optional::bevy_xpbd_plugin::BevyXpbdEditorPlugin); - } - register_mesh_editor_bundles(app); register_light_editor_bundles(app); } diff --git a/src/editor/ui/bot_menu.rs b/src/editor/ui/bot_menu.rs index 2dc89669..8a7131c5 100644 --- a/src/editor/ui/bot_menu.rs +++ b/src/editor/ui/bot_menu.rs @@ -2,7 +2,7 @@ use bevy::prelude::*; use bevy_egui::*; use crate::{ - editor::core::{EditorEvent, EditorPrefabPath, BackgroundTaskStorage, BackgroundTask}, + editor::core::{BackgroundTask, BackgroundTaskStorage, EditorEvent, EditorPrefabPath}, prefab::PrefabPlugin, EditorSet, EditorState, }; @@ -65,7 +65,7 @@ pub fn bot_menu( mut events: EventReader, mut menu_state: ResMut, mut editor_events: EventWriter, - background_tasks : Res + background_tasks: Res, ) { let ctx = ctxs.ctx_mut(); egui::TopBottomPanel::bottom("bot menu").show(ctx, |ui| { diff --git a/src/editor/ui/change_chain.rs b/src/editor/ui/change_chain.rs index 850b1ce0..17a6e09b 100644 --- a/src/editor/ui/change_chain.rs +++ b/src/editor/ui/change_chain.rs @@ -1,30 +1,35 @@ use bevy::prelude::*; -use crate::editor::core::ChangeChain; use super::{editor_tab::EditorTab, EditorUiAppExt}; +use crate::editor::core::ChangeChain; pub struct ChangeChainViewPlugin; impl Plugin for ChangeChainViewPlugin { fn build(&self, app: &mut App) { - app.editor_tab_by_trait(super::editor_tab::EditorTabName::Other("Change Chain".to_string()), ChangeChainView::default()); + app.editor_tab_by_trait( + super::editor_tab::EditorTabName::Other("Change Chain".to_string()), + ChangeChainView::default(), + ); } } #[derive(Resource)] -pub struct ChangeChainView { - -} +pub struct ChangeChainView {} impl Default for ChangeChainView { fn default() -> Self { - Self { - } + Self {} } } impl EditorTab for ChangeChainView { - fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands: &mut bevy::prelude::Commands, world: &mut bevy::prelude::World) { + fn ui( + &mut self, + ui: &mut bevy_egui::egui::Ui, + commands: &mut bevy::prelude::Commands, + world: &mut bevy::prelude::World, + ) { let change_chain = world.resource::(); for change in change_chain.changes.iter() { @@ -35,4 +40,4 @@ impl EditorTab for ChangeChainView { fn title(&self) -> bevy_egui::egui::WidgetText { "Change Chain".into() } -} \ No newline at end of file +} diff --git a/src/editor/ui/game_view.rs b/src/editor/ui/game_view.rs index 6a4da088..b88681ee 100644 --- a/src/editor/ui/game_view.rs +++ b/src/editor/ui/game_view.rs @@ -2,7 +2,11 @@ use bevy::{prelude::*, window::PrimaryWindow}; use bevy_egui::egui::{self}; use egui_gizmo::GizmoMode; -use crate::{editor::core::{EditorTool, UndoRedo}, prelude::EditorTab, EditorCameraMarker}; +use crate::{ + editor::core::{EditorTool, UndoRedo}, + prelude::EditorTab, + EditorCameraMarker, +}; #[derive(Resource)] pub struct GameViewTab { @@ -27,8 +31,8 @@ impl Default for GameViewTab { impl EditorTab for GameViewTab { fn ui(&mut self, ui: &mut bevy_egui::egui::Ui, commands: &mut Commands, world: &mut World) { - - if ui.input_mut(|i| i.key_released(egui::Key::Z) && i.modifiers.ctrl && !i.modifiers.shift) { + if ui.input_mut(|i| i.key_released(egui::Key::Z) && i.modifiers.ctrl && !i.modifiers.shift) + { world.send_event(UndoRedo::Undo); info!("Undo command"); } diff --git a/src/editor/ui/inspector/mod.rs b/src/editor/ui/inspector/mod.rs index 42ef6a46..e30e2d06 100644 --- a/src/editor/ui/inspector/mod.rs +++ b/src/editor/ui/inspector/mod.rs @@ -3,10 +3,10 @@ pub mod refl_impl; use std::any::TypeId; use bevy::{ - ecs::{change_detection::MutUntyped, system::CommandQueue, component::ComponentId}, + ecs::{change_detection::MutUntyped, system::CommandQueue}, prelude::*, ptr::PtrMut, - reflect::{ReflectFromPtr, DynamicStruct}, utils::HashMap, scene::DynamicEntity, + reflect::ReflectFromPtr, }; use bevy_egui::*; @@ -47,14 +47,11 @@ impl Plugin for SpaceInspectorPlugin { } #[derive(Resource, Default)] -pub struct InspectorTab { - default_opened : HashMap, - undo_cache : HashMap -} +pub struct InspectorTab {} impl EditorTab for InspectorTab { fn ui(&mut self, ui: &mut egui::Ui, _: &mut Commands, world: &mut World) { - inspect(self, ui, world); + inspect(ui, world); } fn title(&self) -> egui::WidgetText { @@ -125,7 +122,7 @@ fn execute_inspect_command( } /// System to show inspector panel -pub fn inspect(tab : &mut InspectorTab, ui: &mut egui::Ui, world: &mut World) { +pub fn inspect(ui: &mut egui::Ui, world: &mut World) { let selected = world .query_filtered::>() .iter(world) @@ -138,7 +135,6 @@ pub fn inspect(tab : &mut InspectorTab, ui: &mut egui::Ui, world: &mut World) { let world_registry = app_registry.read(); let disable_pan_orbit = false; - //Collet data about all components //Collet data about all components let mut components_id = Vec::new(); for reg in registry.iter() { @@ -147,19 +143,10 @@ pub fn inspect(tab : &mut InspectorTab, ui: &mut egui::Ui, world: &mut World) { world.components().get_info(c_id).unwrap().name(), ); components_id.push((c_id, reg.type_id(), name)); - let name = pretty_type_name::pretty_type_name_str( - world.components().get_info(c_id).unwrap().name(), - ); - components_id.push((c_id, reg.type_id(), name)); } } components_id.sort_by(|a, b| a.2.cmp(&b.2)); - unsafe { - let cell = world.as_unsafe_world_cell(); - let mut state = cell.get_resource_mut::().unwrap(); - components_id.sort_by(|a, b| a.2.cmp(&b.2)); - let cell = world.as_unsafe_world_cell(); let mut state = unsafe { cell.get_resource_mut::().unwrap() }; diff --git a/src/editor/ui/mod.rs b/src/editor/ui/mod.rs index 90b33bbb..a8632e2f 100644 --- a/src/editor/ui/mod.rs +++ b/src/editor/ui/mod.rs @@ -186,44 +186,44 @@ impl EditorUi { let cell = world.as_unsafe_world_cell(); - unsafe { - let mut command_queue = CommandQueue::default(); - let mut commands = Commands::new(&mut command_queue, cell.world()); + let mut command_queue = CommandQueue::default(); + let mut commands = Commands::new(&mut command_queue, unsafe { cell.world() }); - let mut tab_viewer = EditorTabViewer { + let mut tab_viewer = unsafe { + EditorTabViewer { commands: &mut commands, world: cell.world_mut(), registry: &mut self.registry, visible, tab_commands: vec![], - }; - - DockArea::new(&mut self.tree) - .show_add_buttons(true) - .show_add_popup(true) - .show(ctx, &mut tab_viewer); - - for command in tab_viewer.tab_commands { - match command { - EditorTabCommand::Add { - name, - surface, - node, - } => { - if let Some(surface) = self.tree.get_surface_mut(surface) { - surface - .node_tree_mut() - .unwrap() - .split_right(node, 0.5, vec![name]); - } + } + }; + + DockArea::new(&mut self.tree) + .show_add_buttons(true) + .show_add_popup(true) + .show(ctx, &mut tab_viewer); + + for command in tab_viewer.tab_commands { + match command { + EditorTabCommand::Add { + name, + surface, + node, + } => { + if let Some(surface) = self.tree.get_surface_mut(surface) { + surface + .node_tree_mut() + .unwrap() + .split_right(node, 0.5, vec![name]); } } } + } + unsafe { command_queue.apply(cell.world_mut()); } - - command_queue.apply(unsafe { cell.world_mut() }); } } diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index 93afab87..b7096693 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -16,7 +16,8 @@ impl Plugin for SettingsWindowPlugin { #[cfg(feature = "bevy_xpbd_3d")] { - #[cfg(feature = "persistance_editor")] { + #[cfg(feature = "persistance_editor")] + { app.persistance_resource::(); app.register_type::>(); app.register_type::>(); From 9de69f14489de4426239b4febb8d9096ab1b2728 Mon Sep 17 00:00:00 2001 From: rewin Date: Fri, 24 Nov 2023 23:37:31 +0300 Subject: [PATCH 24/35] Hotkey base --- src/editor/core/hotkeys.rs | 34 ++++++++++++++++++++++++++++++++++ src/editor/core/mod.rs | 3 +++ 2 files changed, 37 insertions(+) create mode 100644 src/editor/core/hotkeys.rs diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs new file mode 100644 index 00000000..dbfa7828 --- /dev/null +++ b/src/editor/core/hotkeys.rs @@ -0,0 +1,34 @@ +use bevy::prelude::*; +use bevy::reflect::GetTypeRegistration; +use bevy::utils::HashMap; + +use super::AppPersistanceExt; + + +#[derive(Resource, Reflect)] +pub struct HotkeySet { + pub bindings : HashMap>, +} + +impl Default for HotkeySet { + fn default() -> Self { + Self { bindings : HashMap::new() } + } +} + +pub trait HotkeyAppExt { + fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self; +} + +impl HotkeyAppExt for App { + fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self { + if !self.world.contains_resource::>() { + self.insert_resource(HotkeySet:: { bindings : HashMap::new() }); + self.persistance_resource::>(); + } + + let mut set = self.world.get_resource_mut::>().unwrap(); + set.bindings.insert(key, binding); + self + } +} \ No newline at end of file diff --git a/src/editor/core/mod.rs b/src/editor/core/mod.rs index 11981e13..61a5ee6a 100644 --- a/src/editor/core/mod.rs +++ b/src/editor/core/mod.rs @@ -13,6 +13,9 @@ pub use task_storage::*; pub mod undo; pub use undo::*; +pub mod hotkeys; +pub use hotkeys::*; + #[cfg(feature = "persistance_editor")] pub mod persistance; #[cfg(feature = "persistance_editor")] From 445b035e57cc1aeaaedb894876b822482a23687d Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 00:00:35 +0300 Subject: [PATCH 25/35] Update hotkeys.rs --- src/editor/core/hotkeys.rs | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index dbfa7828..ba6caae7 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -4,31 +4,63 @@ use bevy::utils::HashMap; use super::AppPersistanceExt; +//TODO: I think this must be a derive macro in future +pub trait Hotkey { + fn name<'a>(&self) -> &'a str; +} + +pub trait UntypedHotkeySet { + +} #[derive(Resource, Reflect)] pub struct HotkeySet { pub bindings : HashMap>, } -impl Default for HotkeySet { +impl Default for HotkeySet +where T : PartialEq + Eq + std::hash::Hash + Reflect + FromReflect { + fn default() -> Self { Self { bindings : HashMap::new() } } } pub trait HotkeyAppExt { - fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self; + fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self; } impl HotkeyAppExt for App { - fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self { + fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self { if !self.world.contains_resource::>() { self.insert_resource(HotkeySet:: { bindings : HashMap::new() }); + self.init_resource::>(); self.persistance_resource::>(); + self.add_systems(PreUpdate, hotkey_mapper::); } let mut set = self.world.get_resource_mut::>().unwrap(); set.bindings.insert(key, binding); self } +} + +fn hotkey_mapper( + bindings : Res>, + mut hotkeys : ResMut>, + input : Res>, +) where T : Copy + PartialEq + Eq + std::hash::Hash + Send + Sync + Reflect + FromReflect + GetTypeRegistration + TypePath + 'static { + for (key, binding) in bindings.bindings.iter() { + let mut pressed = true; + for code in binding { + if !input.pressed(*code) { + pressed = false; + } + } + if pressed { + hotkeys.press(*key); + } else { + hotkeys.release(*key); + } + } } \ No newline at end of file From f2ae60b9837a3a250704a18e32bd231bd1aba40b Mon Sep 17 00:00:00 2001 From: Julia Naomi Date: Fri, 24 Nov 2023 15:02:12 -0600 Subject: [PATCH 26/35] Simplifies entity naming (#76) Close #75 * simplifies-entity-naming * adds-paratensis --- src/editor/ui/hierarchy.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/editor/ui/hierarchy.rs b/src/editor/ui/hierarchy.rs index f903a258..8bc716e1 100644 --- a/src/editor/ui/hierarchy.rs +++ b/src/editor/ui/hierarchy.rs @@ -61,7 +61,7 @@ pub fn show_hierarchy( let ui = &mut ui.0; egui::ScrollArea::vertical().show(ui, |ui| { - for (entity, _, _, parent) in all.iter() { + for (entity, _name, _children, parent) in all.iter() { if parent.is_none() { draw_entity( &mut commands, @@ -118,8 +118,8 @@ fn draw_entity( }; let entity_name = name.map_or_else( - || format!("Entity {:?}", entity), - |name| format!("Entity {:?}: {:?}", entity, name.as_str()), + || format!("Entity ({:?})", entity), + |name| format!("{} ({:?})", name.as_str(), entity), ); ui.indent(entity_name.clone(), |ui| { From 3403dd73a8bbe32737d364917b877cc7ce8f60f8 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 01:27:15 +0300 Subject: [PATCH 27/35] Semi worked hotkeys --- Cargo.toml | 2 +- src/editor/core/hotkeys.rs | 67 ++++++++++++++++++++++++++++-------- src/editor/ui/mod.rs | 3 +- src/editor/ui/settings.rs | 66 +++++++++++++++++++++++++++-------- src/editor/ui/tools/gizmo.rs | 39 ++++++++++++++++++--- 5 files changed, 142 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9c378d18..9625d346 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ opt-level = 3 [features] bevy_xpbd_3d = ["dep:bevy_xpbd_3d", "bevy_xpbd_3d/debug-plugin", "bevy_xpbd_3d/3d", "bevy_xpbd_3d/collider-from-mesh", "bevy_xpbd_3d/f32"] -default = ["bevy_xpbd_3d"] +default = ["bevy_xpbd_3d", "persistance_editor"] persistance_editor = [] [[example]] diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index ba6caae7..4b87cd6e 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -1,42 +1,79 @@ +use bevy::ecs::change_detection::MutUntyped; use bevy::prelude::*; use bevy::reflect::GetTypeRegistration; -use bevy::utils::HashMap; +use bevy::utils::{HashMap, HashSet}; use super::AppPersistanceExt; //TODO: I think this must be a derive macro in future -pub trait Hotkey { - fn name<'a>(&self) -> &'a str; +pub trait Hotkey : Send + Sync + Reflect + FromReflect + GetTypeRegistration + TypePath + PartialEq + Eq + Copy + std::hash::Hash + 'static { + fn name<'a>(&self) -> String; } -pub trait UntypedHotkeySet { - -} - -#[derive(Resource, Reflect)] -pub struct HotkeySet { +#[derive(Resource, Reflect, Deref)] +pub struct HotkeySet { pub bindings : HashMap>, } impl Default for HotkeySet -where T : PartialEq + Eq + std::hash::Hash + Reflect + FromReflect { - +where T : Hotkey { fn default() -> Self { Self { bindings : HashMap::new() } } } +#[derive(Resource, Default)] +pub struct AllHotkeys { + pub mappers : Vec)) + Send + Sync>> +} + +impl AllHotkeys { + pub fn map(&self, world : &mut World, map_fun : &mut dyn FnMut(&mut World, String, &mut Vec)) { + for mapper in &self.mappers { + mapper(world, map_fun); + } + } +} + +pub trait UntypedHotkeySet { + fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec)>; +} + +impl UntypedHotkeySet for HotkeySet { + fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec)> { + self.bindings.iter_mut().map(|(k, v)| (k.name(), v)).collect() + } +} + pub trait HotkeyAppExt { - fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self; + fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self; } impl HotkeyAppExt for App { - fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self { + fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self { + + if !self.world.contains_resource::() { + self.insert_resource(AllHotkeys::default()); + } + if !self.world.contains_resource::>() { self.insert_resource(HotkeySet:: { bindings : HashMap::new() }); self.init_resource::>(); self.persistance_resource::>(); self.add_systems(PreUpdate, hotkey_mapper::); + self.register_type::>(); + self.register_type::>(); + self.register_type::>>(); + self.register_type::(); + self.world.resource_mut::() + .mappers + .push(Box::new(|w, map_fun| { + w.resource_scope::, _>(|world, mut set| { + for (name, binding) in set.get_flat_bindings() { + map_fun(world, name, binding); + } + }); + })); } let mut set = self.world.get_resource_mut::>().unwrap(); @@ -49,7 +86,8 @@ fn hotkey_mapper( bindings : Res>, mut hotkeys : ResMut>, input : Res>, -) where T : Copy + PartialEq + Eq + std::hash::Hash + Send + Sync + Reflect + FromReflect + GetTypeRegistration + TypePath + 'static { +) where T : Hotkey { + hotkeys.clear(); for (key, binding) in bindings.bindings.iter() { let mut pressed = true; for code in binding { @@ -63,4 +101,5 @@ fn hotkey_mapper( hotkeys.release(*key); } } + } \ No newline at end of file diff --git a/src/editor/ui/mod.rs b/src/editor/ui/mod.rs index ddc68378..6895e0f3 100644 --- a/src/editor/ui/mod.rs +++ b/src/editor/ui/mod.rs @@ -38,7 +38,7 @@ use crate::{EditorSet, EditorState}; use self::{ mouse_check::{pointer_context_check, MouseCheck}, - tools::gizmo::GizmoTool, + tools::gizmo::{GizmoTool, GizmoToolPlugin}, }; use super::{ @@ -104,6 +104,7 @@ impl Plugin for EditorUiPlugin { app.add_plugins(SpaceInspectorPlugin); app.editor_tool(GizmoTool::default()); + app.add_plugins(GizmoToolPlugin); app.world.resource_mut::().active_tool = Some(0); app.add_plugins(settings::SettingsWindowPlugin); diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index b7096693..e92e121e 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy_egui::*; -use crate::prelude::{EditorTab, EditorTabName}; +use crate::{prelude::{EditorTab, EditorTabName}, editor::core::AllHotkeys}; #[cfg(feature = "persistance_editor")] use crate::prelude::editor::core::AppPersistanceExt; @@ -29,7 +29,9 @@ impl Plugin for SettingsWindowPlugin { } #[derive(Default, Resource)] -pub struct SettingsWindow {} +pub struct SettingsWindow { + read_input_for_hotkey : Option +} impl EditorTab for SettingsWindow { fn ui(&mut self, ui: &mut egui::Ui, _commands: &mut Commands, world: &mut World) { @@ -52,6 +54,54 @@ impl EditorTab for SettingsWindow { ui.heading("Hotkeys in Game view tab"); + if world.contains_resource::() { + egui::Grid::new("hotkeys_grid").num_columns(2).show(ui, |ui| { + world.resource_scope::(|world,all_hotkeys| { + all_hotkeys.map(world, &mut |world, hotkey_name, bindings| { + ui.label(&hotkey_name); + + if let Some(read_input_for_hotkey) = &self.read_input_for_hotkey { + if hotkey_name == *read_input_for_hotkey { + ui.button("Wait for input"); + + world.resource_scope::, _>(|world, input| { + for key in input.get_just_pressed() { + bindings.clear(); + bindings.push(*key); + self.read_input_for_hotkey = None; + } + }); + } else { + let mut binding_text = "".to_string(); + if bindings.len() == 1 { + binding_text = format!("{:?}", &bindings[0]); + } else { + binding_text = format!("{:?}", bindings); + } + + if ui.button(binding_text).clicked() { + self.read_input_for_hotkey = Some(hotkey_name); + } + } + } else { + let mut binding_text = "".to_string(); + if bindings.len() == 1 { + binding_text = format!("{:?}", &bindings[0]); + } else { + binding_text = format!("{:?}", bindings); + } + + if ui.button(binding_text).clicked() { + self.read_input_for_hotkey = Some(hotkey_name); + } + } + + ui.end_row(); + }); + }); + }); + } + egui::Grid::new("hotkeys") .num_columns(2) .striped(true) @@ -60,18 +110,6 @@ impl EditorTab for SettingsWindow { ui.label("Left mouse button"); ui.end_row(); - ui.label("Move object"); - ui.label("G"); - ui.end_row(); - - ui.label("Rotate object"); - ui.label("R"); - ui.end_row(); - - ui.label("Scale object"); - ui.label("S"); - ui.end_row(); - ui.label("Move/rotate/scale/clone \nmany objects simultaneously"); ui.label("Shift"); ui.end_row(); diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 89cf710e..91c8c584 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -3,11 +3,38 @@ use bevy_egui::egui::{self, Key}; use egui_gizmo::*; use crate::{ - editor::core::{EditorTool, Selected}, + editor::core::{EditorTool, Selected, Hotkey, HotkeySet, HotkeyAppExt}, prelude::CloneEvent, EditorCameraMarker, }; +pub struct GizmoToolPlugin; + +impl Plugin for GizmoToolPlugin { + fn build(&self, app: &mut App) { + app.editor_hotkey(GizmoHotkey::Translate, vec![KeyCode::G]); + app.editor_hotkey(GizmoHotkey::Rotate, vec![KeyCode::R]); + app.editor_hotkey(GizmoHotkey::Scale, vec![KeyCode::S]); + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect)] +pub enum GizmoHotkey { + Translate, + Rotate, + Scale, +} + +impl Hotkey for GizmoHotkey { + fn name<'a>(&self) -> String { + match self { + GizmoHotkey::Translate => "Translate entity".to_string(), + GizmoHotkey::Rotate => "Rotate entity".to_string(), + GizmoHotkey::Scale => "Scale entity".to_string(), + } + } +} + pub struct GizmoTool { pub gizmo_mode: GizmoMode, pub is_move_cloned_entities: bool, @@ -64,13 +91,15 @@ impl EditorTool for GizmoTool { if ui.ui_contains_pointer() && !ui.ctx().wants_keyboard_input() { //hot keys. Blender keys preffer let mode2key = vec![ - (GizmoMode::Translate, Key::G), - (GizmoMode::Rotate, Key::R), - (GizmoMode::Scale, Key::S), + (GizmoMode::Translate, GizmoHotkey::Translate), + (GizmoMode::Rotate, GizmoHotkey::Rotate), + (GizmoMode::Scale, GizmoHotkey::Scale), ]; + let input = world.resource::>(); + for (mode, key) in mode2key { - if ui.input(|s| s.key_pressed(key)) { + if input.just_pressed(key) { self.gizmo_mode = mode; } } From 1ca558755a467bba18629cb42d410c9dfe6c2764 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 01:28:08 +0300 Subject: [PATCH 28/35] cargo fmt and update from main --- src/editor/core/hotkeys.rs | 70 +++++++++++++++++++++++++----------- src/editor/ui/settings.rs | 67 ++++++++++++++++++---------------- src/editor/ui/tools/gizmo.rs | 2 +- 3 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index 4b87cd6e..e97b3085 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -6,29 +6,53 @@ use bevy::utils::{HashMap, HashSet}; use super::AppPersistanceExt; //TODO: I think this must be a derive macro in future -pub trait Hotkey : Send + Sync + Reflect + FromReflect + GetTypeRegistration + TypePath + PartialEq + Eq + Copy + std::hash::Hash + 'static { +pub trait Hotkey: + Send + + Sync + + Reflect + + FromReflect + + GetTypeRegistration + + TypePath + + PartialEq + + Eq + + Copy + + std::hash::Hash + + 'static +{ fn name<'a>(&self) -> String; } #[derive(Resource, Reflect, Deref)] -pub struct HotkeySet { - pub bindings : HashMap>, +pub struct HotkeySet { + pub bindings: HashMap>, } impl Default for HotkeySet -where T : Hotkey { +where + T: Hotkey, +{ fn default() -> Self { - Self { bindings : HashMap::new() } + Self { + bindings: HashMap::new(), + } } } #[derive(Resource, Default)] pub struct AllHotkeys { - pub mappers : Vec)) + Send + Sync>> + pub mappers: Vec< + Box< + dyn Fn(&mut World, &mut dyn FnMut(&mut World, String, &mut Vec)) + Send + Sync, + >, + >, } impl AllHotkeys { - pub fn map(&self, world : &mut World, map_fun : &mut dyn FnMut(&mut World, String, &mut Vec)) { + pub fn map( + &self, + world: &mut World, + map_fun: &mut dyn FnMut(&mut World, String, &mut Vec), + ) { for mapper in &self.mappers { mapper(world, map_fun); } @@ -39,25 +63,29 @@ pub trait UntypedHotkeySet { fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec)>; } -impl UntypedHotkeySet for HotkeySet { +impl UntypedHotkeySet for HotkeySet { fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec)> { - self.bindings.iter_mut().map(|(k, v)| (k.name(), v)).collect() + self.bindings + .iter_mut() + .map(|(k, v)| (k.name(), v)) + .collect() } } pub trait HotkeyAppExt { - fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self; + fn editor_hotkey(&mut self, key: T, binding: Vec) -> &mut Self; } impl HotkeyAppExt for App { - fn editor_hotkey(&mut self, key : T, binding : Vec) -> &mut Self { - + fn editor_hotkey(&mut self, key: T, binding: Vec) -> &mut Self { if !self.world.contains_resource::() { self.insert_resource(AllHotkeys::default()); } if !self.world.contains_resource::>() { - self.insert_resource(HotkeySet:: { bindings : HashMap::new() }); + self.insert_resource(HotkeySet:: { + bindings: HashMap::new(), + }); self.init_resource::>(); self.persistance_resource::>(); self.add_systems(PreUpdate, hotkey_mapper::); @@ -65,7 +93,8 @@ impl HotkeyAppExt for App { self.register_type::>(); self.register_type::>>(); self.register_type::(); - self.world.resource_mut::() + self.world + .resource_mut::() .mappers .push(Box::new(|w, map_fun| { w.resource_scope::, _>(|world, mut set| { @@ -83,10 +112,12 @@ impl HotkeyAppExt for App { } fn hotkey_mapper( - bindings : Res>, - mut hotkeys : ResMut>, - input : Res>, -) where T : Hotkey { + bindings: Res>, + mut hotkeys: ResMut>, + input: Res>, +) where + T: Hotkey, +{ hotkeys.clear(); for (key, binding) in bindings.bindings.iter() { let mut pressed = true; @@ -101,5 +132,4 @@ fn hotkey_mapper( hotkeys.release(*key); } } - -} \ No newline at end of file +} diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index e92e121e..976882b3 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -1,7 +1,10 @@ use bevy::prelude::*; use bevy_egui::*; -use crate::{prelude::{EditorTab, EditorTabName}, editor::core::AllHotkeys}; +use crate::{ + editor::core::AllHotkeys, + prelude::{EditorTab, EditorTabName}, +}; #[cfg(feature = "persistance_editor")] use crate::prelude::editor::core::AppPersistanceExt; @@ -30,7 +33,7 @@ impl Plugin for SettingsWindowPlugin { #[derive(Default, Resource)] pub struct SettingsWindow { - read_input_for_hotkey : Option + read_input_for_hotkey: Option, } impl EditorTab for SettingsWindow { @@ -55,22 +58,36 @@ impl EditorTab for SettingsWindow { ui.heading("Hotkeys in Game view tab"); if world.contains_resource::() { - egui::Grid::new("hotkeys_grid").num_columns(2).show(ui, |ui| { - world.resource_scope::(|world,all_hotkeys| { - all_hotkeys.map(world, &mut |world, hotkey_name, bindings| { - ui.label(&hotkey_name); - - if let Some(read_input_for_hotkey) = &self.read_input_for_hotkey { - if hotkey_name == *read_input_for_hotkey { - ui.button("Wait for input"); - - world.resource_scope::, _>(|world, input| { - for key in input.get_just_pressed() { - bindings.clear(); - bindings.push(*key); - self.read_input_for_hotkey = None; + egui::Grid::new("hotkeys_grid") + .num_columns(2) + .show(ui, |ui| { + world.resource_scope::(|world, all_hotkeys| { + all_hotkeys.map(world, &mut |world, hotkey_name, bindings| { + ui.label(&hotkey_name); + + if let Some(read_input_for_hotkey) = &self.read_input_for_hotkey { + if hotkey_name == *read_input_for_hotkey { + ui.button("Wait for input"); + + world.resource_scope::, _>(|world, input| { + for key in input.get_just_pressed() { + bindings.clear(); + bindings.push(*key); + self.read_input_for_hotkey = None; + } + }); + } else { + let mut binding_text = "".to_string(); + if bindings.len() == 1 { + binding_text = format!("{:?}", &bindings[0]); + } else { + binding_text = format!("{:?}", bindings); + } + + if ui.button(binding_text).clicked() { + self.read_input_for_hotkey = Some(hotkey_name); } - }); + } } else { let mut binding_text = "".to_string(); if bindings.len() == 1 { @@ -83,23 +100,11 @@ impl EditorTab for SettingsWindow { self.read_input_for_hotkey = Some(hotkey_name); } } - } else { - let mut binding_text = "".to_string(); - if bindings.len() == 1 { - binding_text = format!("{:?}", &bindings[0]); - } else { - binding_text = format!("{:?}", bindings); - } - if ui.button(binding_text).clicked() { - self.read_input_for_hotkey = Some(hotkey_name); - } - } - - ui.end_row(); + ui.end_row(); + }); }); }); - }); } egui::Grid::new("hotkeys") diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 91c8c584..8e0e5c7f 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -3,7 +3,7 @@ use bevy_egui::egui::{self, Key}; use egui_gizmo::*; use crate::{ - editor::core::{EditorTool, Selected, Hotkey, HotkeySet, HotkeyAppExt}, + editor::core::{EditorTool, Hotkey, HotkeyAppExt, HotkeySet, Selected}, prelude::CloneEvent, EditorCameraMarker, }; From 10a35e1ef1533edf6195779c05c93ed72d30e6fa Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 01:31:58 +0300 Subject: [PATCH 29/35] cargo clippy --- src/editor/core/hotkeys.rs | 6 +++--- src/editor/ui/settings.rs | 22 ++++++++++------------ src/editor/ui/tools/gizmo.rs | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index e97b3085..a1c3cde4 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -1,7 +1,7 @@ -use bevy::ecs::change_detection::MutUntyped; + use bevy::prelude::*; use bevy::reflect::GetTypeRegistration; -use bevy::utils::{HashMap, HashSet}; +use bevy::utils::HashMap; use super::AppPersistanceExt; @@ -19,7 +19,7 @@ pub trait Hotkey: + std::hash::Hash + 'static { - fn name<'a>(&self) -> String; + fn name(&self) -> String; } #[derive(Resource, Reflect, Deref)] diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index 976882b3..353a26f1 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -67,9 +67,9 @@ impl EditorTab for SettingsWindow { if let Some(read_input_for_hotkey) = &self.read_input_for_hotkey { if hotkey_name == *read_input_for_hotkey { - ui.button("Wait for input"); + let _ = ui.button("Wait for input"); - world.resource_scope::, _>(|world, input| { + world.resource_scope::, _>(|_world, input| { for key in input.get_just_pressed() { bindings.clear(); bindings.push(*key); @@ -77,24 +77,22 @@ impl EditorTab for SettingsWindow { } }); } else { - let mut binding_text = "".to_string(); - if bindings.len() == 1 { - binding_text = format!("{:?}", &bindings[0]); + let binding_text =if bindings.len() == 1 { + format!("{:?}", &bindings[0]) } else { - binding_text = format!("{:?}", bindings); - } + format!("{:?}", bindings) + }; if ui.button(binding_text).clicked() { self.read_input_for_hotkey = Some(hotkey_name); } } } else { - let mut binding_text = "".to_string(); - if bindings.len() == 1 { - binding_text = format!("{:?}", &bindings[0]); + let binding_text = if bindings.len() == 1 { + format!("{:?}", &bindings[0]) } else { - binding_text = format!("{:?}", bindings); - } + format!("{:?}", bindings) + }; if ui.button(binding_text).clicked() { self.read_input_for_hotkey = Some(hotkey_name); diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 8e0e5c7f..47d5935a 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -3,7 +3,7 @@ use bevy_egui::egui::{self, Key}; use egui_gizmo::*; use crate::{ - editor::core::{EditorTool, Hotkey, HotkeyAppExt, HotkeySet, Selected}, + editor::core::{EditorTool, Hotkey, HotkeyAppExt, Selected}, prelude::CloneEvent, EditorCameraMarker, }; From 2e647b3e1b1ea5ef6c197737230d2b59382d7686 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 01:43:31 +0300 Subject: [PATCH 30/35] Update settings.rs --- src/editor/ui/settings.rs | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index 353a26f1..bf0850dc 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -105,26 +105,26 @@ impl EditorTab for SettingsWindow { }); } - egui::Grid::new("hotkeys") - .num_columns(2) - .striped(true) - .show(ui, |ui| { - ui.label("Select object"); - ui.label("Left mouse button"); - ui.end_row(); - - ui.label("Move/rotate/scale/clone \nmany objects simultaneously"); - ui.label("Shift"); - ui.end_row(); - - ui.label("Clone object"); - ui.label("Alt"); - ui.end_row(); - - ui.label("Delete object"); - ui.label("Delete or X"); - ui.end_row(); - }); + // egui::Grid::new("hotkeys") + // .num_columns(2) + // .striped(true) + // .show(ui, |ui| { + // ui.label("Select object"); + // ui.label("Left mouse button"); + // ui.end_row(); + + // ui.label("Move/rotate/scale/clone \nmany objects simultaneously"); + // ui.label("Shift"); + // ui.end_row(); + + // ui.label("Clone object"); + // ui.label("Alt"); + // ui.end_row(); + + // ui.label("Delete object"); + // ui.label("Delete or X"); + // ui.end_row(); + // }); } fn title(&self) -> egui::WidgetText { From 739c956bc507be631cf66a9bc27a46bd78c1da38 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 14:10:05 +0300 Subject: [PATCH 31/35] Multiple keys --- src/editor/core/hotkeys.rs | 1 - src/editor/ui/settings.rs | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index a1c3cde4..f6eaa217 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -1,4 +1,3 @@ - use bevy::prelude::*; use bevy::reflect::GetTypeRegistration; use bevy::utils::HashMap; diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index bf0850dc..f43071be 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -1,4 +1,4 @@ -use bevy::prelude::*; +use bevy::{prelude::*, utils::HashSet}; use bevy_egui::*; use crate::{ @@ -34,6 +34,7 @@ impl Plugin for SettingsWindowPlugin { #[derive(Default, Resource)] pub struct SettingsWindow { read_input_for_hotkey: Option, + all_pressed_hotkeys: HashSet, } impl EditorTab for SettingsWindow { @@ -67,17 +68,43 @@ impl EditorTab for SettingsWindow { if let Some(read_input_for_hotkey) = &self.read_input_for_hotkey { if hotkey_name == *read_input_for_hotkey { - let _ = ui.button("Wait for input"); + let mut key_text = String::new(); world.resource_scope::, _>(|_world, input| { - for key in input.get_just_pressed() { + let all_pressed = + input.get_pressed().map(|k| *k).collect::>(); + self.all_pressed_hotkeys.extend(all_pressed.iter()); + let all_pressed = self + .all_pressed_hotkeys + .iter() + .map(|k| *k) + .collect::>(); + + if all_pressed.len() == 0 { + key_text = "Wait for input".to_string(); + } else { + key_text = format!("{:?}", all_pressed[0]); + for idx in 1..all_pressed.len() { + key_text = format!( + "{} + {:?}", + key_text, all_pressed[idx] + ); + } + } + + if input.get_just_released().len() > 0 { bindings.clear(); - bindings.push(*key); + *bindings = all_pressed; self.read_input_for_hotkey = None; + self.all_pressed_hotkeys.clear(); } + + ui.add(egui::Button::new( + egui::RichText::new(key_text).strong(), + )); }); } else { - let binding_text =if bindings.len() == 1 { + let binding_text = if bindings.len() == 1 { format!("{:?}", &bindings[0]) } else { format!("{:?}", bindings) From b210f5b60617800fa33204855c7198cefb2c78d9 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 14:54:15 +0300 Subject: [PATCH 32/35] Improve persistance and clean ui --- src/editor/core/hotkeys.rs | 48 ++++++++++++--- src/editor/core/persistance.rs | 58 +++++++++++++++++-- src/editor/ui/settings.rs | 103 +++++++++++++++++---------------- src/editor/ui/tools/gizmo.rs | 37 +++++++++--- 4 files changed, 174 insertions(+), 72 deletions(-) diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index f6eaa217..677a106a 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -21,9 +21,10 @@ pub trait Hotkey: fn name(&self) -> String; } -#[derive(Resource, Reflect, Deref)] +#[derive(Resource, Reflect)] pub struct HotkeySet { pub bindings: HashMap>, + pub name : String } impl Default for HotkeySet @@ -33,6 +34,7 @@ where fn default() -> Self { Self { bindings: HashMap::new(), + name : T::short_type_path().to_string() } } } @@ -44,6 +46,9 @@ pub struct AllHotkeys { dyn Fn(&mut World, &mut dyn FnMut(&mut World, String, &mut Vec)) + Send + Sync, >, >, + pub global_mapper : Vec< + Box + > } impl AllHotkeys { @@ -56,18 +61,36 @@ impl AllHotkeys { mapper(world, map_fun); } } + + pub fn global_map( + &self, + world: &mut World, + map_fun: &mut dyn FnMut(&mut World, &mut dyn UntypedHotkeySet), + ) { + for mapper in &self.global_mapper { + mapper(world, map_fun); + } + } } pub trait UntypedHotkeySet { fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec)>; + fn get_name(&self) -> &str; } impl UntypedHotkeySet for HotkeySet { fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec)> { - self.bindings + let mut res = self.bindings .iter_mut() .map(|(k, v)| (k.name(), v)) - .collect() + .collect::>(); + + res.sort_by(|a, b| a.0.cmp(&b.0)); + res + } + + fn get_name(&self) -> &str { + &self.name } } @@ -82,11 +105,13 @@ impl HotkeyAppExt for App { } if !self.world.contains_resource::>() { - self.insert_resource(HotkeySet:: { - bindings: HashMap::new(), - }); + self.insert_resource(HotkeySet::::default()); self.init_resource::>(); - self.persistance_resource::>(); + self.persistance_resource_with_fn::>( + Box::new(|dst : &mut HotkeySet, src : HotkeySet| { + dst.bindings.extend(src.bindings); + }) + ); self.add_systems(PreUpdate, hotkey_mapper::); self.register_type::>(); self.register_type::>(); @@ -102,6 +127,15 @@ impl HotkeyAppExt for App { } }); })); + + self.world + .resource_mut::() + .global_mapper + .push(Box::new(|w, map_fun| { + w.resource_scope::, _>(|world, mut set| { + map_fun(world, set.as_mut()); + }) + })) } let mut set = self.world.get_resource_mut::>().unwrap(); diff --git a/src/editor/core/persistance.rs b/src/editor/core/persistance.rs index 2defeda6..97600374 100644 --- a/src/editor/core/persistance.rs +++ b/src/editor/core/persistance.rs @@ -135,7 +135,7 @@ fn persistance_end(mut persistance: ResMut) { } PersistanceMode::Loading => { persistance.mode = PersistanceMode::None; - if persistance.load_counter == persistance.target_count { + if persistance.load_counter != persistance.target_count { error!( "Persistance loading error: {} of {} resources were loaded", persistance.load_counter, persistance.target_count @@ -215,13 +215,31 @@ impl Default for PersistanceDataSource { Self::File("editor.ron".to_string()) } } +#[derive(Resource)] +struct PersistanceLoadPipeline { + pub load_fn : Box +} + +impl Default for PersistanceLoadPipeline { + fn default() -> Self { + Self { + load_fn: Box::new(|dst, src| {*dst = src;}), + } + } +} pub trait AppPersistanceExt { fn persistance_resource( &mut self, ) -> &mut Self; + + fn persistance_resource_with_fn( + &mut self, + load_function : Box + ) -> &mut Self; } + impl AppPersistanceExt for App { fn persistance_resource( &mut self, @@ -233,6 +251,29 @@ impl AppPersistanceExt for App { self.register_type::(); self.add_event::>(); + self.init_resource::>(); + + self.add_systems( + Update, + persistance_resource_system::.in_set(PersistanceSet::ResourceProcess), + ); + + self + } + + fn persistance_resource_with_fn( + &mut self, + load_function : Box + ) -> &mut Self { + self.world + .resource_mut::() + .target_count += 1; + + self.register_type::(); + self.add_event::>(); + + self.insert_resource(PersistanceLoadPipeline{load_fn : load_function}); + self.add_systems( Update, persistance_resource_system::.in_set(PersistanceSet::ResourceProcess), @@ -242,14 +283,13 @@ impl AppPersistanceExt for App { } } -fn persistance_resource_system< - T: Default + Reflect + FromReflect + Resource + GetTypeRegistration, ->( +fn persistance_resource_system( mut events: EventReader, mut persistance: ResMut, mut resource: ResMut, registry: Res, mut persistance_loaded: EventWriter>, + mut pipeline : ResMut>, ) { for event in events.read() { match event { @@ -283,8 +323,14 @@ fn persistance_resource_system< .deserialize(&mut ron::Deserializer::from_str(data).unwrap()) .unwrap(); - let converted = ::from_reflect(&*reflected_value).unwrap(); - *resource = converted; + let Some(converted) = ::from_reflect(&*reflected_value) else { + warn!( + "Persistance resource {} could not be converted", + T::get_type_registration().type_info().type_path() + ); + continue; + }; + (pipeline.load_fn)(resource.as_mut(), converted); resource.set_changed(); persistance_loaded.send(PersistanceLoaded::::default()); diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index f43071be..c4329fc9 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -56,53 +56,66 @@ impl EditorTab for SettingsWindow { ); } - ui.heading("Hotkeys in Game view tab"); - if world.contains_resource::() { egui::Grid::new("hotkeys_grid") .num_columns(2) .show(ui, |ui| { world.resource_scope::(|world, all_hotkeys| { - all_hotkeys.map(world, &mut |world, hotkey_name, bindings| { - ui.label(&hotkey_name); - - if let Some(read_input_for_hotkey) = &self.read_input_for_hotkey { - if hotkey_name == *read_input_for_hotkey { - let mut key_text = String::new(); - - world.resource_scope::, _>(|_world, input| { - let all_pressed = - input.get_pressed().map(|k| *k).collect::>(); - self.all_pressed_hotkeys.extend(all_pressed.iter()); - let all_pressed = self - .all_pressed_hotkeys - .iter() - .map(|k| *k) - .collect::>(); - - if all_pressed.len() == 0 { - key_text = "Wait for input".to_string(); - } else { - key_text = format!("{:?}", all_pressed[0]); - for idx in 1..all_pressed.len() { - key_text = format!( - "{} + {:?}", - key_text, all_pressed[idx] - ); + all_hotkeys.global_map(world, &mut |world, set| { + ui.heading(set.get_name()); + ui.end_row(); + let all_bindings = set.get_flat_bindings(); + for (hotkey_name, bindings) in all_bindings { + ui.label(&hotkey_name); + + if let Some(read_input_for_hotkey) = &self.read_input_for_hotkey { + if hotkey_name == *read_input_for_hotkey { + let mut key_text = String::new(); + + world.resource_scope::, _>(|_world, input| { + let all_pressed = + input.get_pressed().map(|k| *k).collect::>(); + self.all_pressed_hotkeys.extend(all_pressed.iter()); + let all_pressed = self + .all_pressed_hotkeys + .iter() + .map(|k| *k) + .collect::>(); + + if all_pressed.len() == 0 { + key_text = "Wait for input".to_string(); + } else { + key_text = format!("{:?}", all_pressed[0]); + for idx in 1..all_pressed.len() { + key_text = format!( + "{} + {:?}", + key_text, all_pressed[idx] + ); + } } - } - if input.get_just_released().len() > 0 { - bindings.clear(); - *bindings = all_pressed; - self.read_input_for_hotkey = None; - self.all_pressed_hotkeys.clear(); - } + if input.get_just_released().len() > 0 { + bindings.clear(); + *bindings = all_pressed; + self.read_input_for_hotkey = None; + self.all_pressed_hotkeys.clear(); + } - ui.add(egui::Button::new( - egui::RichText::new(key_text).strong(), - )); - }); + ui.add(egui::Button::new( + egui::RichText::new(key_text).strong(), + )); + }); + } else { + let binding_text = if bindings.len() == 1 { + format!("{:?}", &bindings[0]) + } else { + format!("{:?}", bindings) + }; + + if ui.button(binding_text).clicked() { + self.read_input_for_hotkey = Some(hotkey_name); + } + } } else { let binding_text = if bindings.len() == 1 { format!("{:?}", &bindings[0]) @@ -114,19 +127,9 @@ impl EditorTab for SettingsWindow { self.read_input_for_hotkey = Some(hotkey_name); } } - } else { - let binding_text = if bindings.len() == 1 { - format!("{:?}", &bindings[0]) - } else { - format!("{:?}", bindings) - }; - if ui.button(binding_text).clicked() { - self.read_input_for_hotkey = Some(hotkey_name); - } + ui.end_row(); } - - ui.end_row(); }); }); }); diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 47d5935a..17da0d82 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -15,6 +15,9 @@ impl Plugin for GizmoToolPlugin { app.editor_hotkey(GizmoHotkey::Translate, vec![KeyCode::G]); app.editor_hotkey(GizmoHotkey::Rotate, vec![KeyCode::R]); app.editor_hotkey(GizmoHotkey::Scale, vec![KeyCode::S]); + app.editor_hotkey(GizmoHotkey::Delete, vec![KeyCode::X]); + app.editor_hotkey(GizmoHotkey::Multiple, vec![KeyCode::ShiftLeft]); + app.editor_hotkey(GizmoHotkey::Clone, vec![KeyCode::AltLeft]); } } @@ -23,6 +26,9 @@ pub enum GizmoHotkey { Translate, Rotate, Scale, + Delete, + Multiple, + Clone, } impl Hotkey for GizmoHotkey { @@ -31,6 +37,9 @@ impl Hotkey for GizmoHotkey { GizmoHotkey::Translate => "Translate entity".to_string(), GizmoHotkey::Rotate => "Rotate entity".to_string(), GizmoHotkey::Scale => "Scale entity".to_string(), + GizmoHotkey::Delete => "Delete entity".to_string(), + GizmoHotkey::Multiple => "Change multiple entities".to_string(), + GizmoHotkey::Clone => "Clone entity".to_string(), } } } @@ -60,6 +69,7 @@ impl EditorTool for GizmoTool { // If SHIFT pressed draw "mean" gizmo to move all selected entities together // If ALT pressed, then entity will be cloned at interact // If SHIFT+ALT pressed, then all selected entities will be cloned at interact + // All hotkeys can be changes in editor ui let mode2name = vec![ (GizmoMode::Translate, "⬌", "Translate"), @@ -87,6 +97,9 @@ impl EditorTool for GizmoTool { }); let mut del = false; + let mut clone_pressed = false; + let mut multiple_pressed = false; + if ui.ui_contains_pointer() && !ui.ctx().wants_keyboard_input() { //hot keys. Blender keys preffer @@ -104,9 +117,19 @@ impl EditorTool for GizmoTool { } } - if ui.input(|s| s.key_pressed(Key::Delete) || s.key_pressed(Key::X)) { + if ui.input(|s| s.key_pressed(Key::Delete) || input.just_pressed(GizmoHotkey::Delete)) { del = true; } + + if !input.pressed(GizmoHotkey::Clone) { + self.is_move_cloned_entities = false; + } else { + clone_pressed = true; + } + + if input.pressed(GizmoHotkey::Multiple) { + multiple_pressed = true; + } } if del { @@ -126,10 +149,6 @@ impl EditorTool for GizmoTool { (*ref_tr, ref_cam.clone()) }; - if ui.input(|s| !s.modifiers.alt) { - self.is_move_cloned_entities = false; - } - let selected = world .query_filtered::>() .iter(world) @@ -140,7 +159,7 @@ impl EditorTool for GizmoTool { let cell = world.as_unsafe_world_cell(); let view_matrix = Mat4::from(cam_transform.affine().inverse()); - if ui.input(|s| s.modifiers.shift) { + if multiple_pressed { let mut mean_transform = Transform::IDENTITY; for e in &selected { let Some(ecell) = cell.get_entity(*e) else { @@ -189,7 +208,7 @@ impl EditorTool for GizmoTool { global_mean = GlobalTransform::from(mean_transform); - if gizmo_interacted && ui.input(|s| s.modifiers.alt) { + if gizmo_interacted && clone_pressed { if self.is_move_cloned_entities { } else { for e in selected.iter() { @@ -252,7 +271,7 @@ impl EditorTool for GizmoTool { scale: Vec3::from(<[f32; 3]>::from(result.scale)), }; - if ui.input(|s| s.modifiers.alt) { + if clone_pressed { if self.is_move_cloned_entities { let new_transform = GlobalTransform::from(new_transform); @@ -284,7 +303,7 @@ impl EditorTool for GizmoTool { .mode(self.gizmo_mode) .interact(ui) { - if ui.input(|s| s.modifiers.alt) { + if clone_pressed { if self.is_move_cloned_entities { *transform = Transform { translation: Vec3::from(<[f32; 3]>::from(result.translation)), From 71bd1c416a0ae6aadee58a87667df5e0819a97d1 Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 15:00:57 +0300 Subject: [PATCH 33/35] fix hotkey build --- src/editor/core/hotkeys.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index 677a106a..6bd537d6 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -2,6 +2,8 @@ use bevy::prelude::*; use bevy::reflect::GetTypeRegistration; use bevy::utils::HashMap; + +#[cfg(feature = "persistance_editor")] use super::AppPersistanceExt; //TODO: I think this must be a derive macro in future @@ -107,11 +109,13 @@ impl HotkeyAppExt for App { if !self.world.contains_resource::>() { self.insert_resource(HotkeySet::::default()); self.init_resource::>(); - self.persistance_resource_with_fn::>( - Box::new(|dst : &mut HotkeySet, src : HotkeySet| { - dst.bindings.extend(src.bindings); - }) - ); + #[cfg(feature = "persistance_editor")] { + self.persistance_resource_with_fn::>( + Box::new(|dst : &mut HotkeySet, src : HotkeySet| { + dst.bindings.extend(src.bindings); + }) + ); + } self.add_systems(PreUpdate, hotkey_mapper::); self.register_type::>(); self.register_type::>(); From 573fbe426c6bc63527a84c4c4e55893463cbf62b Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 15:02:58 +0300 Subject: [PATCH 34/35] clippy fix --- src/editor/core/persistance.rs | 2 +- src/editor/ui/settings.rs | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/editor/core/persistance.rs b/src/editor/core/persistance.rs index 97600374..b2c65ddb 100644 --- a/src/editor/core/persistance.rs +++ b/src/editor/core/persistance.rs @@ -289,7 +289,7 @@ fn persistance_resource_system, registry: Res, mut persistance_loaded: EventWriter>, - mut pipeline : ResMut>, + pipeline : ResMut>, ) { for event in events.read() { match event { diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index c4329fc9..206ccd58 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -74,22 +74,21 @@ impl EditorTab for SettingsWindow { world.resource_scope::, _>(|_world, input| { let all_pressed = - input.get_pressed().map(|k| *k).collect::>(); + input.get_pressed().copied().collect::>(); self.all_pressed_hotkeys.extend(all_pressed.iter()); let all_pressed = self .all_pressed_hotkeys - .iter() - .map(|k| *k) + .iter().copied() .collect::>(); - if all_pressed.len() == 0 { + if all_pressed.is_empty() { key_text = "Wait for input".to_string(); } else { key_text = format!("{:?}", all_pressed[0]); - for idx in 1..all_pressed.len() { + for key in all_pressed.iter().skip(1) { key_text = format!( "{} + {:?}", - key_text, all_pressed[idx] + key_text, key ); } } @@ -102,7 +101,7 @@ impl EditorTab for SettingsWindow { } ui.add(egui::Button::new( - egui::RichText::new(key_text).strong(), + egui::RichText::new(&key_text).strong(), )); }); } else { From f6036f9104bd5186ef3896f79882d4a33b0c094d Mon Sep 17 00:00:00 2001 From: rewin Date: Sat, 25 Nov 2023 15:04:11 +0300 Subject: [PATCH 35/35] format fix --- src/editor/core/hotkeys.rs | 29 ++++++++------- src/editor/core/persistance.rs | 29 +++++++++------ src/editor/ui/settings.rs | 65 ++++++++++++++++++---------------- src/editor/ui/tools/gizmo.rs | 1 - 4 files changed, 69 insertions(+), 55 deletions(-) diff --git a/src/editor/core/hotkeys.rs b/src/editor/core/hotkeys.rs index 6bd537d6..18816502 100644 --- a/src/editor/core/hotkeys.rs +++ b/src/editor/core/hotkeys.rs @@ -2,7 +2,6 @@ use bevy::prelude::*; use bevy::reflect::GetTypeRegistration; use bevy::utils::HashMap; - #[cfg(feature = "persistance_editor")] use super::AppPersistanceExt; @@ -26,7 +25,7 @@ pub trait Hotkey: #[derive(Resource, Reflect)] pub struct HotkeySet { pub bindings: HashMap>, - pub name : String + pub name: String, } impl Default for HotkeySet @@ -36,7 +35,7 @@ where fn default() -> Self { Self { bindings: HashMap::new(), - name : T::short_type_path().to_string() + name: T::short_type_path().to_string(), } } } @@ -48,9 +47,11 @@ pub struct AllHotkeys { dyn Fn(&mut World, &mut dyn FnMut(&mut World, String, &mut Vec)) + Send + Sync, >, >, - pub global_mapper : Vec< - Box - > + pub global_mapper: Vec< + Box< + dyn Fn(&mut World, &mut dyn FnMut(&mut World, &mut dyn UntypedHotkeySet)) + Send + Sync, + >, + >, } impl AllHotkeys { @@ -82,11 +83,12 @@ pub trait UntypedHotkeySet { impl UntypedHotkeySet for HotkeySet { fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec)> { - let mut res = self.bindings + let mut res = self + .bindings .iter_mut() .map(|(k, v)| (k.name(), v)) .collect::>(); - + res.sort_by(|a, b| a.0.cmp(&b.0)); res } @@ -109,12 +111,13 @@ impl HotkeyAppExt for App { if !self.world.contains_resource::>() { self.insert_resource(HotkeySet::::default()); self.init_resource::>(); - #[cfg(feature = "persistance_editor")] { - self.persistance_resource_with_fn::>( - Box::new(|dst : &mut HotkeySet, src : HotkeySet| { + #[cfg(feature = "persistance_editor")] + { + self.persistance_resource_with_fn::>(Box::new( + |dst: &mut HotkeySet, src: HotkeySet| { dst.bindings.extend(src.bindings); - }) - ); + }, + )); } self.add_systems(PreUpdate, hotkey_mapper::); self.register_type::>(); diff --git a/src/editor/core/persistance.rs b/src/editor/core/persistance.rs index b2c65ddb..772cdbc1 100644 --- a/src/editor/core/persistance.rs +++ b/src/editor/core/persistance.rs @@ -217,13 +217,15 @@ impl Default for PersistanceDataSource { } #[derive(Resource)] struct PersistanceLoadPipeline { - pub load_fn : Box + pub load_fn: Box, } impl Default for PersistanceLoadPipeline { fn default() -> Self { Self { - load_fn: Box::new(|dst, src| {*dst = src;}), + load_fn: Box::new(|dst, src| { + *dst = src; + }), } } } @@ -233,13 +235,14 @@ pub trait AppPersistanceExt { &mut self, ) -> &mut Self; - fn persistance_resource_with_fn( + fn persistance_resource_with_fn< + T: Default + Reflect + FromReflect + Resource + GetTypeRegistration, + >( &mut self, - load_function : Box + load_function: Box, ) -> &mut Self; } - impl AppPersistanceExt for App { fn persistance_resource( &mut self, @@ -261,9 +264,11 @@ impl AppPersistanceExt for App { self } - fn persistance_resource_with_fn( + fn persistance_resource_with_fn< + T: Default + Reflect + FromReflect + Resource + GetTypeRegistration, + >( &mut self, - load_function : Box + load_function: Box, ) -> &mut Self { self.world .resource_mut::() @@ -272,7 +277,9 @@ impl AppPersistanceExt for App { self.register_type::(); self.add_event::>(); - self.insert_resource(PersistanceLoadPipeline{load_fn : load_function}); + self.insert_resource(PersistanceLoadPipeline { + load_fn: load_function, + }); self.add_systems( Update, @@ -283,13 +290,15 @@ impl AppPersistanceExt for App { } } -fn persistance_resource_system( +fn persistance_resource_system< + T: Default + Reflect + FromReflect + Resource + GetTypeRegistration, +>( mut events: EventReader, mut persistance: ResMut, mut resource: ResMut, registry: Res, mut persistance_loaded: EventWriter>, - pipeline : ResMut>, + pipeline: ResMut>, ) { for event in events.read() { match event { diff --git a/src/editor/ui/settings.rs b/src/editor/ui/settings.rs index 206ccd58..5b3d7e3d 100644 --- a/src/editor/ui/settings.rs +++ b/src/editor/ui/settings.rs @@ -72,38 +72,41 @@ impl EditorTab for SettingsWindow { if hotkey_name == *read_input_for_hotkey { let mut key_text = String::new(); - world.resource_scope::, _>(|_world, input| { - let all_pressed = - input.get_pressed().copied().collect::>(); - self.all_pressed_hotkeys.extend(all_pressed.iter()); - let all_pressed = self - .all_pressed_hotkeys - .iter().copied() - .collect::>(); - - if all_pressed.is_empty() { - key_text = "Wait for input".to_string(); - } else { - key_text = format!("{:?}", all_pressed[0]); - for key in all_pressed.iter().skip(1) { - key_text = format!( - "{} + {:?}", - key_text, key - ); + world.resource_scope::, _>( + |_world, input| { + let all_pressed = input + .get_pressed() + .copied() + .collect::>(); + self.all_pressed_hotkeys.extend(all_pressed.iter()); + let all_pressed = self + .all_pressed_hotkeys + .iter() + .copied() + .collect::>(); + + if all_pressed.is_empty() { + key_text = "Wait for input".to_string(); + } else { + key_text = format!("{:?}", all_pressed[0]); + for key in all_pressed.iter().skip(1) { + key_text = + format!("{} + {:?}", key_text, key); + } } - } - - if input.get_just_released().len() > 0 { - bindings.clear(); - *bindings = all_pressed; - self.read_input_for_hotkey = None; - self.all_pressed_hotkeys.clear(); - } - - ui.add(egui::Button::new( - egui::RichText::new(&key_text).strong(), - )); - }); + + if input.get_just_released().len() > 0 { + bindings.clear(); + *bindings = all_pressed; + self.read_input_for_hotkey = None; + self.all_pressed_hotkeys.clear(); + } + + ui.add(egui::Button::new( + egui::RichText::new(&key_text).strong(), + )); + }, + ); } else { let binding_text = if bindings.len() == 1 { format!("{:?}", &bindings[0]) diff --git a/src/editor/ui/tools/gizmo.rs b/src/editor/ui/tools/gizmo.rs index 17da0d82..00b35573 100644 --- a/src/editor/ui/tools/gizmo.rs +++ b/src/editor/ui/tools/gizmo.rs @@ -100,7 +100,6 @@ impl EditorTool for GizmoTool { let mut clone_pressed = false; let mut multiple_pressed = false; - if ui.ui_contains_pointer() && !ui.ctx().wants_keyboard_input() { //hot keys. Blender keys preffer let mode2key = vec![