Skip to content

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
naomijub committed Nov 25, 2023
2 parents acba0fd + 637a501 commit 3515895
Show file tree
Hide file tree
Showing 7 changed files with 407 additions and 53 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]]
Expand Down
175 changes: 175 additions & 0 deletions src/editor/core/hotkeys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
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
pub trait Hotkey:
Send
+ Sync
+ Reflect
+ FromReflect
+ GetTypeRegistration
+ TypePath
+ PartialEq
+ Eq
+ Copy
+ std::hash::Hash
+ 'static
{
fn name(&self) -> String;
}

#[derive(Resource, Reflect)]
pub struct HotkeySet<T: Hotkey> {
pub bindings: HashMap<T, Vec<KeyCode>>,
pub name: String,
}

impl<T> Default for HotkeySet<T>
where
T: Hotkey,
{
fn default() -> Self {
Self {
bindings: HashMap::new(),
name: T::short_type_path().to_string(),
}
}
}

#[derive(Resource, Default)]
pub struct AllHotkeys {
pub mappers: Vec<
Box<
dyn Fn(&mut World, &mut dyn FnMut(&mut World, String, &mut Vec<KeyCode>)) + Send + Sync,
>,
>,
pub global_mapper: Vec<
Box<
dyn Fn(&mut World, &mut dyn FnMut(&mut World, &mut dyn UntypedHotkeySet)) + Send + Sync,
>,
>,
}

impl AllHotkeys {
pub fn map(
&self,
world: &mut World,
map_fun: &mut dyn FnMut(&mut World, String, &mut Vec<KeyCode>),
) {
for mapper in &self.mappers {
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<KeyCode>)>;
fn get_name(&self) -> &str;
}

impl<T: Hotkey> UntypedHotkeySet for HotkeySet<T> {
fn get_flat_bindings(&mut self) -> Vec<(String, &mut Vec<KeyCode>)> {
let mut res = self
.bindings
.iter_mut()
.map(|(k, v)| (k.name(), v))
.collect::<Vec<_>>();

res.sort_by(|a, b| a.0.cmp(&b.0));
res
}

fn get_name(&self) -> &str {
&self.name
}
}

pub trait HotkeyAppExt {
fn editor_hotkey<T: Hotkey>(&mut self, key: T, binding: Vec<KeyCode>) -> &mut Self;
}

impl HotkeyAppExt for App {
fn editor_hotkey<T: Hotkey>(&mut self, key: T, binding: Vec<KeyCode>) -> &mut Self {
if !self.world.contains_resource::<AllHotkeys>() {
self.insert_resource(AllHotkeys::default());
}

if !self.world.contains_resource::<HotkeySet<T>>() {
self.insert_resource(HotkeySet::<T>::default());
self.init_resource::<Input<T>>();
#[cfg(feature = "persistance_editor")]
{
self.persistance_resource_with_fn::<HotkeySet<T>>(Box::new(
|dst: &mut HotkeySet<T>, src: HotkeySet<T>| {
dst.bindings.extend(src.bindings);
},
));
}
self.add_systems(PreUpdate, hotkey_mapper::<T>);
self.register_type::<Vec<KeyCode>>();
self.register_type::<HotkeySet<T>>();
self.register_type::<HashMap<T, Vec<KeyCode>>>();
self.register_type::<T>();
self.world
.resource_mut::<AllHotkeys>()
.mappers
.push(Box::new(|w, map_fun| {
w.resource_scope::<HotkeySet<T>, _>(|world, mut set| {
for (name, binding) in set.get_flat_bindings() {
map_fun(world, name, binding);
}
});
}));

self.world
.resource_mut::<AllHotkeys>()
.global_mapper
.push(Box::new(|w, map_fun| {
w.resource_scope::<HotkeySet<T>, _>(|world, mut set| {
map_fun(world, set.as_mut());
})
}))
}

let mut set = self.world.get_resource_mut::<HotkeySet<T>>().unwrap();
set.bindings.insert(key, binding);
self
}
}

fn hotkey_mapper<T>(
bindings: Res<HotkeySet<T>>,
mut hotkeys: ResMut<Input<T>>,
input: Res<Input<KeyCode>>,
) where
T: Hotkey,
{
hotkeys.clear();
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);
}
}
}
3 changes: 3 additions & 0 deletions src/editor/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
61 changes: 58 additions & 3 deletions src/editor/core/persistance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ fn persistance_end(mut persistance: ResMut<PersistanceRegistry>) {
}
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
Expand Down Expand Up @@ -215,11 +215,32 @@ impl Default for PersistanceDataSource {
Self::File("editor.ron".to_string())
}
}
#[derive(Resource)]
struct PersistanceLoadPipeline<T> {
pub load_fn: Box<dyn Fn(&mut T, T) + Send + Sync>,
}

impl<T> Default for PersistanceLoadPipeline<T> {
fn default() -> Self {
Self {
load_fn: Box::new(|dst, src| {
*dst = src;
}),
}
}
}

pub trait AppPersistanceExt {
fn persistance_resource<T: Default + Reflect + FromReflect + Resource + GetTypeRegistration>(
&mut self,
) -> &mut Self;

fn persistance_resource_with_fn<
T: Default + Reflect + FromReflect + Resource + GetTypeRegistration,
>(
&mut self,
load_function: Box<dyn Fn(&mut T, T) + Send + Sync>,
) -> &mut Self;
}

impl AppPersistanceExt for App {
Expand All @@ -233,6 +254,33 @@ impl AppPersistanceExt for App {
self.register_type::<T>();
self.add_event::<PersistanceLoaded<T>>();

self.init_resource::<PersistanceLoadPipeline<T>>();

self.add_systems(
Update,
persistance_resource_system::<T>.in_set(PersistanceSet::ResourceProcess),
);

self
}

fn persistance_resource_with_fn<
T: Default + Reflect + FromReflect + Resource + GetTypeRegistration,
>(
&mut self,
load_function: Box<dyn Fn(&mut T, T) + Send + Sync>,
) -> &mut Self {
self.world
.resource_mut::<PersistanceRegistry>()
.target_count += 1;

self.register_type::<T>();
self.add_event::<PersistanceLoaded<T>>();

self.insert_resource(PersistanceLoadPipeline {
load_fn: load_function,
});

self.add_systems(
Update,
persistance_resource_system::<T>.in_set(PersistanceSet::ResourceProcess),
Expand All @@ -250,6 +298,7 @@ fn persistance_resource_system<
mut resource: ResMut<T>,
registry: Res<AppTypeRegistry>,
mut persistance_loaded: EventWriter<PersistanceLoaded<T>>,
pipeline: ResMut<PersistanceLoadPipeline<T>>,
) {
for event in events.read() {
match event {
Expand Down Expand Up @@ -283,8 +332,14 @@ fn persistance_resource_system<
.deserialize(&mut ron::Deserializer::from_str(data).unwrap())
.unwrap();

let converted = <T as FromReflect>::from_reflect(&*reflected_value).unwrap();
*resource = converted;
let Some(converted) = <T as FromReflect>::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::<T>::default());
Expand Down
3 changes: 2 additions & 1 deletion src/editor/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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::<GameViewTab>().active_tool = Some(0);

app.add_plugins(settings::SettingsWindowPlugin);
Expand Down
Loading

0 comments on commit 3515895

Please sign in to comment.