From ef055a1bda1f627c8e28fc51196e425e99980c53 Mon Sep 17 00:00:00 2001 From: reo Date: Wed, 15 Oct 2025 22:33:04 +0300 Subject: [PATCH 1/5] Replace contexts with resources - Implements a new macro to generate code for a new structure: TypeMap - TypeMaps are wrappers for HashMaps that use TypeIDs as keys. - Refactor the entire codebase to use the new resource structures. - This commit is the first step towards getting rid of "god context objects everywhere". --- Cargo.toml | 2 +- core/src/engine.rs | 5 +- core/src/lib.rs | 3 +- core/src/scene.rs | 16 +++- core/src/utils/managers.rs | 44 ++++++++++ core/src/utils/mod.rs | 2 + core/src/utils/typemap.rs | 122 ++++++++++++++++++++++++++ engine/src/engine.rs | 85 ++++++++---------- engine/src/lib.rs | 2 + engine/src/resources.rs | 3 + engine/src/system.rs | 9 +- engine/src/systems/fps_camera.rs | 35 +++++--- game/src/main.rs | 37 ++++---- glium_platform/src/platform.rs | 7 +- glium_platform/src/render/debug_ui.rs | 2 +- glium_platform/src/system.rs | 6 +- 16 files changed, 287 insertions(+), 93 deletions(-) create mode 100644 core/src/utils/managers.rs create mode 100644 core/src/utils/mod.rs create mode 100644 core/src/utils/typemap.rs create mode 100644 engine/src/resources.rs diff --git a/Cargo.toml b/Cargo.toml index 102844c..23332d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,5 +6,5 @@ members = [ "asset", "game", "ecs", - "engine" + "engine", ] diff --git a/core/src/engine.rs b/core/src/engine.rs index 80d2a69..b70a945 100644 --- a/core/src/engine.rs +++ b/core/src/engine.rs @@ -11,7 +11,8 @@ pub trait EngineTrait { fn fixed_update(&mut self, platform_context: Self::PlatformCtx); fn handle_event(&mut self, platform_context: Self::PlatformCtx); fn current_scene_mut(&mut self) -> &mut Scene; - fn get_debug_ui_buffer(&self) -> Rc>; + fn current_scene(&self) -> &Scene; + fn get_debug_ui_buffer(&self) -> &DebugUIBuffer; fn reset_debug_ui_buffer(&mut self); - fn scene_and_debug_ui_buffer_mut(&mut self) -> (&mut Scene, Rc>); + // fn scene_and_debug_ui_buffer_mut(&mut self) -> (&mut Self::Scene, &DebugUIBuffer); } diff --git a/core/src/lib.rs b/core/src/lib.rs index 4b7d531..238d5a6 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,6 +1,7 @@ pub mod engine; -pub mod scene; pub mod debug_ui; pub mod time; +pub mod utils; +pub mod scene; pub use debug_ui::*; diff --git a/core/src/scene.rs b/core/src/scene.rs index 9d1a7d4..1a075bf 100644 --- a/core/src/scene.rs +++ b/core/src/scene.rs @@ -1,19 +1,31 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; +use crate::{define_typemap, DebugUIBuffer}; pub struct Scene { pub title: String, pub world: hecs::World, pub skybox_texture_path: Option, + pub resources: SceneResources, } +define_typemap!(SceneResources,); + impl Scene { pub fn new(title: String, skybox_texture_path: Option) -> Self { - Self { + let mut s = Self { title, world: hecs::World::new(), skybox_texture_path, - } + resources: SceneResources::new(), + }; + s.load_default_resources(); + s + } + + pub fn load_default_resources(&mut self) { + let dbg = DebugUIBuffer::new(); + self.resources.insert(dbg); } } diff --git a/core/src/utils/managers.rs b/core/src/utils/managers.rs new file mode 100644 index 0000000..aac2ce7 --- /dev/null +++ b/core/src/utils/managers.rs @@ -0,0 +1,44 @@ +/// Unused as of now. +#[macro_export] +macro_rules! create_manager { + ($manager_name:ident, $trait_name:ident) => { + pub struct $manager_name { + systems: ::indexmap::IndexMap<::std::any::TypeId, Box>, + } + + impl $manager_name { + pub fn new() -> Self { + Self { + systems: ::indexmap::IndexMap::default(), + } + } + + pub fn add(&mut self) { + self.systems + .insert(::std::any::TypeId::of::(), Box::new(S::default())); + } + + pub fn remove(&mut self) { + self.systems.shift_remove(&::std::any::TypeId::of::()); + } + + pub fn for_each_value(&self, mut f: F) + where + F: FnMut(&dyn $trait_name), + { + for value in self.systems.values() { + f(value.as_ref()); + } + } + + pub fn for_each_value_mut(&mut self, mut f: F) + where + F: FnMut(&mut dyn $trait_name), + { + for value in self.systems.values_mut() { + f(value.as_mut()); + } + } + } + }; +} diff --git a/core/src/utils/mod.rs b/core/src/utils/mod.rs new file mode 100644 index 0000000..4a5eaf5 --- /dev/null +++ b/core/src/utils/mod.rs @@ -0,0 +1,2 @@ +pub mod typemap; +mod managers; diff --git a/core/src/utils/typemap.rs b/core/src/utils/typemap.rs new file mode 100644 index 0000000..88d3dc5 --- /dev/null +++ b/core/src/utils/typemap.rs @@ -0,0 +1,122 @@ +#[macro_export] +macro_rules! define_typemap { + ($name:ident, $($trait_bound:tt)*) => { + pub struct $name { + map: std::collections::HashMap>, + } + + impl $name { + pub fn new() -> Self { + Self { + map: std::collections::HashMap::new(), + } + } + + pub fn insert(&mut self, value: T) -> Option> + where + T: std::any::Any + 'static + $($trait_bound)*, + { + let type_id = std::any::TypeId::of::(); + self.map + .insert(type_id, Box::new(value)) + .and_then(|boxed| boxed.downcast().ok()) + } + + pub fn get(&self) -> Option<&T> + where + T: std::any::Any + 'static + $($trait_bound)*, + { + self.map + .get(&std::any::TypeId::of::()) + .and_then(|any| any.downcast_ref::()) + } + + pub fn get_mut(&mut self) -> Option<&mut T> + where + T: std::any::Any + 'static + $($trait_bound)*, + { + self.map + .get_mut(&std::any::TypeId::of::()) + .and_then(|any| any.downcast_mut::()) + } + + pub fn remove(&mut self) -> Option> + where + T: std::any::Any + 'static + $($trait_bound)*, + { + self.map + .remove(&std::any::TypeId::of::()) + .and_then(|boxed| boxed.downcast().ok()) + } + + pub fn len(&self) -> usize { + self.map.len() + } + + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + pub fn clear(&mut self) { + self.map.clear(); + } + + pub fn contains(&self) -> bool + where + T: std::any::Any + 'static + $($trait_bound)*, + { + self.map.contains_key(&std::any::TypeId::of::()) + } + } + + impl Default for $name { + fn default() -> Self { + Self::new() + } + } + }; +} + +// pub struct TypeMap { +// map: HashMap>, +// } +// +// impl TypeMap { +// pub fn new() -> Self { +// Self { +// map: HashMap::new(), +// } +// } +// +// pub fn insert(&mut self, value: T) -> Option> { +// let type_id = TypeId::of::(); +// self.map +// .insert(type_id, Box::new(value)) +// .and_then(|boxed| boxed.downcast().ok()) +// } +// +// pub fn get(&self) -> Option<&T> +// where +// T: Any + 'static, +// { +// self.map.get(&TypeId::of::()) +// .and_then(|any| any.downcast_ref::()) +// } +// +// pub fn get_mut(&mut self) -> Option<&mut T> +// where +// T: Any + 'static, +// { +// self.map.get_mut(&TypeId::of::()).and_then(|any| any.downcast_mut::()) +// } +// +// pub fn remove(&mut self) -> Option> { +// unimplemented!() +// } +// } +// +// impl Default for TypeMap { +// fn default() -> Self { +// Self::new() +// } +// } diff --git a/engine/src/engine.rs b/engine/src/engine.rs index 68f17e0..7c366dc 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -3,15 +3,22 @@ use std::rc::Rc; use raidillon_core::scene::{Scene, SceneManager}; use crate::system::{SystemContext, SystemManager}; use raidillon_platform::PlatformContext; -use raidillon_core::DebugUIBuffer; +use raidillon_core::{define_typemap, DebugUIBuffer}; use raidillon_core::engine::EngineTrait; use crate::input::InputState; +use crate::resources::EngineResources; pub struct Engine { pub scene_manager: SceneManager, pub system_manager: SystemManager, - debug_ui_buffer: Rc>, - input_state: Rc>, + pub resources: EngineResources, +} + +impl Engine { + fn load_default_resources(&mut self) { + let input = InputState::default(); + self.resources.insert(input); + } } impl EngineTrait for Engine { @@ -19,12 +26,13 @@ impl EngineTrait for Engine { fn new() -> Self { let scene_manager = SceneManager::new(); let system_manager = SystemManager::new(); - Self { + let mut s = Self { scene_manager, system_manager, - debug_ui_buffer: Rc::new(RefCell::new(DebugUIBuffer::new())), - input_state: Default::default(), - } + resources: EngineResources::new(), + }; + s.load_default_resources(); + s } /// Initialize systems, load the world. @@ -33,60 +41,35 @@ impl EngineTrait for Engine { for system in self.system_manager.systems.values_mut() { system.initialize(); } - - let mut ctx = SystemContext { - scene: self.scene_manager.current_mut(), - platform_context, - debug_ui_buffer: self.debug_ui_buffer.clone(), - input_state: self.input_state.clone(), - }; - + self.resources.insert(platform_context); // Engine Loading Stage 2: load world for system in self.system_manager.systems.values_mut() { - system.load_world(&mut ctx); + system.load_world(&mut self.resources, &mut self.scene_manager.current_mut()); } } /// Update the engine fn frame_update(&mut self, platform_context: PlatformContext) { - self.debug_ui_buffer.borrow_mut().reset_buffer(); - let mut ctx = SystemContext { - scene: self.scene_manager.current_mut(), - platform_context, - debug_ui_buffer: self.debug_ui_buffer.clone(), - input_state: self.input_state.clone(), - }; + self.scene_manager.current_mut().resources.get_mut::().unwrap().reset_buffer(); + self.resources.insert(platform_context); for system in self.system_manager.systems.values_mut() { - system.frame_update(&mut ctx); + system.frame_update(&mut self.resources, &mut self.scene_manager.current_mut()); } } fn fixed_update(&mut self, platform_context: PlatformContext) { - let mut ctx = SystemContext { - scene: self.scene_manager.current_mut(), - platform_context, - debug_ui_buffer: self.debug_ui_buffer.clone(), - input_state: self.input_state.clone(), - }; - + self.resources.insert(platform_context); for system in self.system_manager.systems.values_mut() { - system.fixed_update(&mut ctx); + system.fixed_update(&mut self.resources, &mut self.scene_manager.current_mut()); } } fn handle_event(&mut self, platform_context: PlatformContext) { - self.input_state.borrow_mut().handle_event(&platform_context.current_event); - - let mut ctx = SystemContext { - scene: self.scene_manager.current_mut(), - platform_context, - debug_ui_buffer: self.debug_ui_buffer.clone(), - input_state: self.input_state.clone(), - }; - + // self.input_state.borrow_mut().handle_event(&platform_context.current_event); + self.resources.insert(platform_context); for system in self.system_manager.systems.values_mut() { - system.handle_event(&mut ctx); + system.handle_event(&mut self.resources, &mut self.scene_manager.current_mut()); } } @@ -100,16 +83,20 @@ impl EngineTrait for Engine { self.scene_manager.current_mut() } - fn get_debug_ui_buffer(&self) -> Rc> { - self.debug_ui_buffer.clone() + fn current_scene(&self) -> &Scene { + self.scene_manager.current() + } + + fn get_debug_ui_buffer(&self) -> &DebugUIBuffer { + self.scene_manager.current().resources.get::().unwrap() } fn reset_debug_ui_buffer(&mut self) { - self.debug_ui_buffer.borrow_mut().reset_buffer(); + self.scene_manager.current_mut().resources.get_mut::().unwrap().reset_buffer(); } - fn scene_and_debug_ui_buffer_mut(&mut self) -> (&mut Scene, Rc>) { - let (sm, dub) = (&mut self.scene_manager, &mut self.debug_ui_buffer); - (sm.current_mut(), dub.clone()) - } + // fn scene_and_debug_ui_buffer_mut(&mut self) -> (&mut Scene, &DebugUIBuffer) { + // let (sm, dub) = (&mut self.scene_manager, self.scene_manager.current().resources.get::().unwrap()); + // (sm.current_mut(), dub) + // } } diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 18ce5fd..9a87556 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -2,5 +2,7 @@ pub mod engine; pub mod system; mod input; pub mod systems; +mod resources; pub use crate::engine::Engine; +pub use crate::resources::EngineResources; diff --git a/engine/src/resources.rs b/engine/src/resources.rs new file mode 100644 index 0000000..cd4be0b --- /dev/null +++ b/engine/src/resources.rs @@ -0,0 +1,3 @@ +use raidillon_core::define_typemap; + +define_typemap!(EngineResources,); diff --git a/engine/src/system.rs b/engine/src/system.rs index b863a75..55cccb1 100644 --- a/engine/src/system.rs +++ b/engine/src/system.rs @@ -6,6 +6,7 @@ use std::any::TypeId; use std::cell::RefCell; use std::rc::Rc; use crate::input::InputState; +use crate::resources::EngineResources; pub struct SystemContext<'a> { pub scene: &'a mut Scene, @@ -18,10 +19,10 @@ pub trait System { /// Initialize the system. fn initialize(&mut self) {} /// Spawn the first entities of the world. - fn load_world(&mut self, _ctx: &mut SystemContext) {} - fn handle_event(&mut self, _ctx: &mut SystemContext) {} - fn fixed_update(&mut self, _ctx: &mut SystemContext) {} - fn frame_update(&mut self, _ctx: &mut SystemContext) {} + fn load_world(&mut self, res: &mut EngineResources, scene: &mut Scene) {} + fn handle_event(&mut self, res: &mut EngineResources, scene: &mut Scene) {} + fn fixed_update(&mut self, res: &mut EngineResources, scene: &mut Scene) {} + fn frame_update(&mut self, res: &mut EngineResources, scene: &mut Scene) {} } pub struct SystemManager { diff --git a/engine/src/systems/fps_camera.rs b/engine/src/systems/fps_camera.rs index 3cc0a3d..6bd99f7 100644 --- a/engine/src/systems/fps_camera.rs +++ b/engine/src/systems/fps_camera.rs @@ -5,7 +5,10 @@ use winit::event::{ElementState, Event, MouseButton, WindowEvent}; use winit::keyboard::{KeyCode, PhysicalKey}; use winit::window::CursorGrabMode; use raidillon_assets::model_path; -use raidillon_platform::Camera; +use raidillon_platform::{Camera, PlatformContext}; +use crate::input::InputState; +use crate::resources::EngineResources; +use raidillon_core::scene::Scene; pub struct FPSDebugCameraSystem { mouse_delta: (f64, f64), @@ -32,20 +35,22 @@ impl Default for FPSDebugCameraSystem { } impl System for FPSDebugCameraSystem { - fn load_world(&mut self, ctx: &mut SystemContext) { - ctx.scene.world.spawn((Camera { + fn load_world(&mut self, res: &mut EngineResources, scene: &mut Scene) { + let pctx = res.get::().unwrap(); + scene.world.spawn((Camera { eye: Vec3::new(0.0, 0.0, 2.0), center: Vec3::ZERO, up: Vec3::Y, fovy: 60_f32.to_radians(), - aspect: ctx.platform_context.frame_width / ctx.platform_context.frame_height, + aspect: pctx.frame_width / pctx.frame_height, znear: 0.1, zfar: 100.0, },)); } - fn handle_event(&mut self, ctx: &mut SystemContext) { - let event2 = ctx.platform_context.current_event.clone(); + fn handle_event(&mut self, res: &mut EngineResources, scene: &mut Scene) { + let pctx = res.get::().unwrap(); + let event2 = pctx.current_event.clone(); match event2 { Event::DeviceEvent { device_id, event} => { match event { @@ -60,7 +65,7 @@ impl System for FPSDebugCameraSystem { WindowEvent::MouseInput { state, button, .. } => { if button == MouseButton::Right { // blood and tear - let window = ctx.platform_context.window.lock().unwrap(); + let window = pctx.window.lock().unwrap(); match state { ElementState::Pressed => { if window @@ -86,7 +91,10 @@ impl System for FPSDebugCameraSystem { } } - fn frame_update(&mut self, ctx: &mut SystemContext) { + fn frame_update(&mut self, res: &mut EngineResources, scene: &mut Scene) { + let pctx = res.get::().unwrap(); + let input = res.get::().unwrap(); + if self.mouse_enabled { self.yaw += self.mouse_delta.0 as f32 * self.sensitivity; self.pitch -= self.mouse_delta.1 as f32 * self.sensitivity; @@ -95,22 +103,21 @@ impl System for FPSDebugCameraSystem { let front = self.front(); let right_vec = front.cross(Vec3::Y).normalize(); - let input = ctx.input_state.borrow_mut(); if input.key_held(KeyCode::KeyW) { - self.position += front * ctx.platform_context.time_ctx.frame_dt * self.speed; + self.position += front * pctx.time_ctx.frame_dt * self.speed; } if input.key_held(KeyCode::KeyS) { - self.position -= front * ctx.platform_context.time_ctx.frame_dt * self.speed; + self.position -= front * pctx.time_ctx.frame_dt * self.speed; } if input.key_held(KeyCode::KeyA) { - self.position -= right_vec * ctx.platform_context.time_ctx.frame_dt * self.speed; + self.position -= right_vec * pctx.time_ctx.frame_dt * self.speed; } if input.key_held(KeyCode::KeyD) { - self.position += right_vec * ctx.platform_context.time_ctx.frame_dt * self.speed; + self.position += right_vec * pctx.time_ctx.frame_dt * self.speed; } - ctx.scene.world.query_mut::<&mut Camera>().into_iter().for_each(|(_, camera)| { + scene.world.query_mut::<&mut Camera>().into_iter().for_each(|(_, camera)| { camera.eye = self.position; camera.center = self.position + front; }); diff --git a/game/src/main.rs b/game/src/main.rs index d5a826b..acedefd 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -1,8 +1,8 @@ use std::fmt::format; use glam::{Quat, Vec3}; -use raidillon_engine::{Engine, system::System}; +use raidillon_engine::{Engine, system::System, EngineResources}; use raidillon_engine::system::SystemContext; -use raidillon_platform::{Platform, Camera}; +use raidillon_platform::{Platform, Camera, PlatformContext}; use raidillon_assets::model_path; use raidillon_core::engine::EngineTrait; use raidillon_ecs::components::ModelHandle; @@ -13,6 +13,7 @@ use raidillon_glium::GliumPlatform; use winit::event::{ElementState, Event, WindowEvent}; use winit::event::DeviceEvent::MouseMotion; use winit::keyboard::{KeyCode, PhysicalKey}; +use raidillon_core::DebugUIBuffer; use raidillon_engine::systems::fps_camera::FPSDebugCameraSystem; const TEST_GLTF: &str = "pink-monkey.gltf"; @@ -22,11 +23,13 @@ const MAIN_SCENE_ID: &str = "main_scene"; #[derive(Default)] struct UpdateAspectRatioSystem; impl System for UpdateAspectRatioSystem { - fn handle_event(&mut self, ctx: &mut SystemContext) { + fn handle_event(&mut self, res: &mut EngineResources, scene: &mut Scene) { + let pctx = res.get::().unwrap(); + if let Event::WindowEvent { event: WindowEvent::Resized(sz), .. } = - &ctx.platform_context.current_event + pctx.current_event { - ctx.scene.world + scene.world .query_mut::<&mut Camera>() .into_iter() .for_each(|(_, cam)| { @@ -42,14 +45,16 @@ struct RenderingTestSystem { } impl System for RenderingTestSystem { - fn load_world(&mut self, ctx: &mut SystemContext) { + fn load_world(&mut self, res: &mut EngineResources, scene: &mut Scene) { + let pctx = res.get::().unwrap(); + self.rotation_speed = std::rc::Rc::new(std::cell::RefCell::new(5.0)); - let mut am = ctx.platform_context.asset_manager.borrow_mut(); + let mut am = pctx.asset_manager.borrow_mut(); am.load_gltf(TEST_GLTF, &model_path(TEST_GLTF)); - ctx.scene.world.spawn(( + scene.world.spawn(( Transform { translation: Vec3::new(0.0, 0.0, 0.0), rotation: Quat::IDENTITY, @@ -59,17 +64,19 @@ impl System for RenderingTestSystem { )); } - fn frame_update(&mut self, ctx: &mut SystemContext) { - let mut dbg_ui = ctx.debug_ui_buffer.borrow_mut(); + fn frame_update(&mut self, res: &mut EngineResources, scene: &mut Scene) { + let pctx = res.get::().unwrap().clone(); + let dbg_ui = scene.resources.get_mut::().unwrap(); dbg_ui.text("Hello World!".to_owned()); - dbg_ui.text(format!("Frame Delta: {}", ctx.platform_context.time_ctx.frame_dt)); - dbg_ui.text(format!("Fixed Delta: {}", ctx.platform_context.time_ctx.fixed_dt)); + dbg_ui.text(format!("Frame Delta: {}", pctx.time_ctx.frame_dt)); + dbg_ui.text(format!("Fixed Delta: {}", pctx.time_ctx.fixed_dt)); dbg_ui.slider_f32("Rotation Speed", -10.0, 10.0, self.rotation_speed.clone()); } - fn fixed_update(&mut self, ctx: &mut SystemContext) { - ctx.scene.world.query_mut::<(&mut Transform, &ModelHandle)>().into_iter().for_each(|(_, (t, _))| { - t.rotation *= Quat::from_rotation_y(*self.rotation_speed.borrow() * ctx.platform_context.time_ctx.fixed_dt); + fn fixed_update(&mut self, res: &mut EngineResources, scene: &mut Scene) { + let pctx = res.get::().unwrap(); + scene.world.query_mut::<(&mut Transform, &ModelHandle)>().into_iter().for_each(|(_, (t, _))| { + t.rotation *= Quat::from_rotation_y(*self.rotation_speed.borrow() * pctx.time_ctx.fixed_dt); }); } diff --git a/glium_platform/src/platform.rs b/glium_platform/src/platform.rs index 9418ab1..db8e56e 100644 --- a/glium_platform/src/platform.rs +++ b/glium_platform/src/platform.rs @@ -98,9 +98,12 @@ impl> Platform for GliumPlatfor WindowEvent::RedrawRequested => { let mut target = self.display.draw(); target.clear_color_and_depth((0.1, 0.1, 0.15, 1.0), 1.0); - let (scene_mut, debug_ui_buffer) = self.engine.scene_and_debug_ui_buffer_mut(); + let (scene, debug_ui_buffer) = ( + self.engine.current_scene(), + self.engine.get_debug_ui_buffer(), + ); let mut context = RenderingContext { - scene: scene_mut, + scene, target: &mut target, asset_manager: self.asset_manager.clone(), window: self.window.clone(), diff --git a/glium_platform/src/render/debug_ui.rs b/glium_platform/src/render/debug_ui.rs index be4ff0d..ac4a06e 100644 --- a/glium_platform/src/render/debug_ui.rs +++ b/glium_platform/src/render/debug_ui.rs @@ -41,7 +41,7 @@ impl RenderingSystem for ImguiBridge { self.rendered_this_frame = true; let ui = self.imgui.frame(); - ctx.debug_ui_buffer.borrow().write_buffer(&ui); + ctx.debug_ui_buffer.write_buffer(&ui); { let window = ctx.window.lock().unwrap(); diff --git a/glium_platform/src/system.rs b/glium_platform/src/system.rs index 3460bc3..51a292f 100644 --- a/glium_platform/src/system.rs +++ b/glium_platform/src/system.rs @@ -6,7 +6,7 @@ use indexmap::IndexMap; use glium::{Display, Frame}; use glium::glutin::surface::WindowSurface; use raidillon_assets::ModelManagerRef; -use raidillon_core::DebugUIBuffer; +use raidillon_core::{define_typemap, DebugUIBuffer}; use raidillon_core::scene::Scene; use glam::Vec3; @@ -15,7 +15,7 @@ pub struct RenderingContext<'a> { pub target: &'a mut Frame, pub window: Arc>, pub asset_manager: ModelManagerRef, - pub debug_ui_buffer: Rc>, + pub debug_ui_buffer: &'a DebugUIBuffer, pub env_light_dir: Vec3, } @@ -35,6 +35,8 @@ pub trait RenderingSystem { Self: Sized; } +// define_typemap!(RenderingSystemManager, RenderingSystem); + pub struct RenderingSystemManager { pub systems: IndexMap>, } From b86bbdd237706dfea4c9e5db182d23d83daab8ed Mon Sep 17 00:00:00 2001 From: reo Date: Thu, 16 Oct 2025 16:11:53 +0300 Subject: [PATCH 2/5] fix spacing --- game/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/game/src/main.rs b/game/src/main.rs index acedefd..4e0ee6e 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -65,8 +65,9 @@ impl System for RenderingTestSystem { } fn frame_update(&mut self, res: &mut EngineResources, scene: &mut Scene) { - let pctx = res.get::().unwrap().clone(); + let pctx = res.get::().unwrap(); let dbg_ui = scene.resources.get_mut::().unwrap(); + dbg_ui.text("Hello World!".to_owned()); dbg_ui.text(format!("Frame Delta: {}", pctx.time_ctx.frame_dt)); dbg_ui.text(format!("Fixed Delta: {}", pctx.time_ctx.fixed_dt)); @@ -75,6 +76,7 @@ impl System for RenderingTestSystem { fn fixed_update(&mut self, res: &mut EngineResources, scene: &mut Scene) { let pctx = res.get::().unwrap(); + scene.world.query_mut::<(&mut Transform, &ModelHandle)>().into_iter().for_each(|(_, (t, _))| { t.rotation *= Quat::from_rotation_y(*self.rotation_speed.borrow() * pctx.time_ctx.fixed_dt); }); From 1a48e58a1cfca6baea4cd60437abfca69fe0d6dd Mon Sep 17 00:00:00 2001 From: reo Date: Thu, 16 Oct 2025 16:12:18 +0300 Subject: [PATCH 3/5] Implement get_many. I believe the repeated code can be generated with procedural macros, but I don't need that right now. I'll do it if I ever end up needing this. Right now I need to start making the game itself more than anything. --- core/src/utils/typemap.rs | 436 +++++++++++++++++++++++++++++-- engine/src/systems/fps_camera.rs | 3 +- 2 files changed, 408 insertions(+), 31 deletions(-) diff --git a/core/src/utils/typemap.rs b/core/src/utils/typemap.rs index 88d3dc5..bd28a66 100644 --- a/core/src/utils/typemap.rs +++ b/core/src/utils/typemap.rs @@ -7,9 +7,7 @@ macro_rules! define_typemap { impl $name { pub fn new() -> Self { - Self { - map: std::collections::HashMap::new(), - } + Self { map: std::collections::HashMap::new() } } pub fn insert(&mut self, value: T) -> Option> @@ -17,49 +15,33 @@ macro_rules! define_typemap { T: std::any::Any + 'static + $($trait_bound)*, { let type_id = std::any::TypeId::of::(); - self.map - .insert(type_id, Box::new(value)) - .and_then(|boxed| boxed.downcast().ok()) + self.map.insert(type_id, Box::new(value)).and_then(|b| b.downcast().ok()) } pub fn get(&self) -> Option<&T> where T: std::any::Any + 'static + $($trait_bound)*, { - self.map - .get(&std::any::TypeId::of::()) - .and_then(|any| any.downcast_ref::()) + self.map.get(&std::any::TypeId::of::())?.downcast_ref::() } pub fn get_mut(&mut self) -> Option<&mut T> where T: std::any::Any + 'static + $($trait_bound)*, { - self.map - .get_mut(&std::any::TypeId::of::()) - .and_then(|any| any.downcast_mut::()) + self.map.get_mut(&std::any::TypeId::of::())?.downcast_mut::() } pub fn remove(&mut self) -> Option> where T: std::any::Any + 'static + $($trait_bound)*, { - self.map - .remove(&std::any::TypeId::of::()) - .and_then(|boxed| boxed.downcast().ok()) + self.map.remove(&std::any::TypeId::of::())?.downcast().ok() } - pub fn len(&self) -> usize { - self.map.len() - } - - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } - - pub fn clear(&mut self) { - self.map.clear(); - } + pub fn len(&self) -> usize { self.map.len() } + pub fn is_empty(&self) -> bool { self.map.is_empty() } + pub fn clear(&mut self) { self.map.clear(); } pub fn contains(&self) -> bool where @@ -67,11 +49,407 @@ macro_rules! define_typemap { { self.map.contains_key(&std::any::TypeId::of::()) } + + // --- tuple-based multi-get API --- + pub fn get_many<'a, T>(&'a self) -> Option<::Output<'a>> + where + T: __tm_get::GetTuple, + { + ::get_from(&self.map) + } + + pub fn get_many_mut<'a, T>(&'a mut self) -> Option<::Output<'a>> + where + T: __tm_get::GetTupleMut, + { + ::get_from_mut(&mut self.map) + } } - impl Default for $name { - fn default() -> Self { - Self::new() + impl Default for $name { fn default() -> Self { Self::new() } } + + // Put helper traits/impls in a private module to avoid name clashes. + mod __tm_get { + use std::any::{Any, TypeId}; + use std::collections::HashMap; + + pub trait GetTuple { + type Output<'a>; + fn get_from<'a>(map: &'a HashMap>) -> Option>; + } + + pub trait GetTupleMut { + type Output<'a>; + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option>; + } + + // Manual implementations for arities 1..=8. + impl GetTuple for (A,) + where + A: Any + 'static, + { + type Output<'a> = (&'a A,); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a,)) + } + } + + impl GetTupleMut for (A,) + where + A: Any + 'static, + { + type Output<'a> = (&'a mut A,); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + Some((a,)) + } + } + } + + impl GetTuple for (A, B) + where + A: Any + 'static, + B: Any + 'static, + { + type Output<'a> = (&'a A, &'a B); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::()]; + if ids[0] == ids[1] { return None; } + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + let b = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a, b)) + } + } + + impl GetTupleMut for (A, B) + where + A: Any + 'static, + B: Any + 'static, + { + type Output<'a> = (&'a mut A, &'a mut B); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::()]; + if ids[0] == ids[1] { return None; } + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_b = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + let b = (&mut *ptr_b).downcast_mut::()?; + Some((a, b)) + } + } + } + + impl GetTuple for (A, B, C) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + { + type Output<'a> = (&'a A, &'a B, &'a C); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; + if ids[0] == ids[1] || ids[0] == ids[2] || ids[1] == ids[2] { return None; } + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + let b = map.get(&TypeId::of::())?.downcast_ref::()?; + let c = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a, b, c)) + } + } + + impl GetTupleMut for (A, B, C) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + { + type Output<'a> = (&'a mut A, &'a mut B, &'a mut C); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::()]; + if ids[0] == ids[1] || ids[0] == ids[2] || ids[1] == ids[2] { return None; } + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_b = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_c = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + let b = (&mut *ptr_b).downcast_mut::()?; + let c = (&mut *ptr_c).downcast_mut::()?; + Some((a, b, c)) + } + } + } + + impl GetTuple for (A, B, C, D) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + { + type Output<'a> = (&'a A, &'a B, &'a C, &'a D); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + let b = map.get(&TypeId::of::())?.downcast_ref::()?; + let c = map.get(&TypeId::of::())?.downcast_ref::()?; + let d = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a, b, c, d)) + } + } + + impl GetTupleMut for (A, B, C, D) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + { + type Output<'a> = (&'a mut A, &'a mut B, &'a mut C, &'a mut D); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_b = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_c = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_d = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + let b = (&mut *ptr_b).downcast_mut::()?; + let c = (&mut *ptr_c).downcast_mut::()?; + let d = (&mut *ptr_d).downcast_mut::()?; + Some((a, b, c, d)) + } + } + } + + impl GetTuple for (A, B, C, D, E) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + { + type Output<'a> = (&'a A, &'a B, &'a C, &'a D, &'a E); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + let b = map.get(&TypeId::of::())?.downcast_ref::()?; + let c = map.get(&TypeId::of::())?.downcast_ref::()?; + let d = map.get(&TypeId::of::())?.downcast_ref::()?; + let e = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a, b, c, d, e)) + } + } + + impl GetTupleMut for (A, B, C, D, E) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + { + type Output<'a> = (&'a mut A, &'a mut B, &'a mut C, &'a mut D, &'a mut E); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_b = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_c = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_d = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_e = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + let b = (&mut *ptr_b).downcast_mut::()?; + let c = (&mut *ptr_c).downcast_mut::()?; + let d = (&mut *ptr_d).downcast_mut::()?; + let e = (&mut *ptr_e).downcast_mut::()?; + Some((a, b, c, d, e)) + } + } + } + + impl GetTuple for (A, B, C, D, E, F) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + F: Any + 'static, + { + type Output<'a> = (&'a A, &'a B, &'a C, &'a D, &'a E, &'a F); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + let b = map.get(&TypeId::of::())?.downcast_ref::()?; + let c = map.get(&TypeId::of::())?.downcast_ref::()?; + let d = map.get(&TypeId::of::())?.downcast_ref::()?; + let e = map.get(&TypeId::of::())?.downcast_ref::()?; + let f = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a, b, c, d, e, f)) + } + } + + impl GetTupleMut for (A, B, C, D, E, F) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + F: Any + 'static, + { + type Output<'a> = (&'a mut A, &'a mut B, &'a mut C, &'a mut D, &'a mut E, &'a mut F); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_b = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_c = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_d = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_e = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_f = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + let b = (&mut *ptr_b).downcast_mut::()?; + let c = (&mut *ptr_c).downcast_mut::()?; + let d = (&mut *ptr_d).downcast_mut::()?; + let e = (&mut *ptr_e).downcast_mut::()?; + let f = (&mut *ptr_f).downcast_mut::()?; + Some((a, b, c, d, e, f)) + } + } + } + + impl GetTuple for (A, B, C, D, E, F, G) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + F: Any + 'static, + G: Any + 'static, + { + type Output<'a> = (&'a A, &'a B, &'a C, &'a D, &'a E, &'a F, &'a G); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + let b = map.get(&TypeId::of::())?.downcast_ref::()?; + let c = map.get(&TypeId::of::())?.downcast_ref::()?; + let d = map.get(&TypeId::of::())?.downcast_ref::()?; + let e = map.get(&TypeId::of::())?.downcast_ref::()?; + let f = map.get(&TypeId::of::())?.downcast_ref::()?; + let g = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a, b, c, d, e, f, g)) + } + } + + impl GetTupleMut for (A, B, C, D, E, F, G) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + F: Any + 'static, + G: Any + 'static, + { + type Output<'a> = (&'a mut A, &'a mut B, &'a mut C, &'a mut D, &'a mut E, &'a mut F, &'a mut G); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_b = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_c = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_d = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_e = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_f = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_g = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + let b = (&mut *ptr_b).downcast_mut::()?; + let c = (&mut *ptr_c).downcast_mut::()?; + let d = (&mut *ptr_d).downcast_mut::()?; + let e = (&mut *ptr_e).downcast_mut::()?; + let f = (&mut *ptr_f).downcast_mut::()?; + let g = (&mut *ptr_g).downcast_mut::()?; + Some((a, b, c, d, e, f, g)) + } + } + } + + impl GetTuple for (A, B, C, D, E, F, G, H) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + F: Any + 'static, + G: Any + 'static, + H: Any + 'static, + { + type Output<'a> = (&'a A, &'a B, &'a C, &'a D, &'a E, &'a F, &'a G, &'a H); + fn get_from<'a>(map: &'a HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let a = map.get(&TypeId::of::())?.downcast_ref::()?; + let b = map.get(&TypeId::of::())?.downcast_ref::()?; + let c = map.get(&TypeId::of::())?.downcast_ref::()?; + let d = map.get(&TypeId::of::())?.downcast_ref::()?; + let e = map.get(&TypeId::of::())?.downcast_ref::()?; + let f = map.get(&TypeId::of::())?.downcast_ref::()?; + let g = map.get(&TypeId::of::())?.downcast_ref::()?; + let h = map.get(&TypeId::of::())?.downcast_ref::()?; + Some((a, b, c, d, e, f, g, h)) + } + } + + impl GetTupleMut for (A, B, C, D, E, F, G, H) + where + A: Any + 'static, + B: Any + 'static, + C: Any + 'static, + D: Any + 'static, + E: Any + 'static, + F: Any + 'static, + G: Any + 'static, + H: Any + 'static, + { + type Output<'a> = (&'a mut A, &'a mut B, &'a mut C, &'a mut D, &'a mut E, &'a mut F, &'a mut G, &'a mut H); + fn get_from_mut<'a>(map: &'a mut HashMap>) -> Option> { + let ids = [TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::(), TypeId::of::()]; + for i in 0..ids.len() { for j in (i+1)..ids.len() { if ids[i] == ids[j] { return None; } } } + let ptr_a = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_b = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_c = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_d = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_e = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_f = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_g = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + let ptr_h = { map.get_mut(&TypeId::of::()).map(|v| v as *mut dyn Any) }?; + unsafe { + let a = (&mut *ptr_a).downcast_mut::()?; + let b = (&mut *ptr_b).downcast_mut::()?; + let c = (&mut *ptr_c).downcast_mut::()?; + let d = (&mut *ptr_d).downcast_mut::()?; + let e = (&mut *ptr_e).downcast_mut::()?; + let f = (&mut *ptr_f).downcast_mut::()?; + let g = (&mut *ptr_g).downcast_mut::()?; + let h = (&mut *ptr_h).downcast_mut::()?; + Some((a, b, c, d, e, f, g, h)) + } + } } } }; diff --git a/engine/src/systems/fps_camera.rs b/engine/src/systems/fps_camera.rs index 6bd99f7..0d98577 100644 --- a/engine/src/systems/fps_camera.rs +++ b/engine/src/systems/fps_camera.rs @@ -92,8 +92,7 @@ impl System for FPSDebugCameraSystem { } fn frame_update(&mut self, res: &mut EngineResources, scene: &mut Scene) { - let pctx = res.get::().unwrap(); - let input = res.get::().unwrap(); + let (pctx, input) = res.get_many::<(PlatformContext, InputState)>().unwrap(); if self.mouse_enabled { self.yaw += self.mouse_delta.0 as f32 * self.sensitivity; From 54967067bdf034e05280c59147ec297071b902d2 Mon Sep 17 00:00:00 2001 From: reo Date: Thu, 16 Oct 2025 17:01:23 +0300 Subject: [PATCH 4/5] Enable InputState event handler in engine --- engine/src/engine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/src/engine.rs b/engine/src/engine.rs index 7c366dc..a5c8a1d 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -66,7 +66,7 @@ impl EngineTrait for Engine { } fn handle_event(&mut self, platform_context: PlatformContext) { - // self.input_state.borrow_mut().handle_event(&platform_context.current_event); + self.resources.get_mut::().unwrap().handle_event(&platform_context.current_event); self.resources.insert(platform_context); for system in self.system_manager.systems.values_mut() { system.handle_event(&mut self.resources, &mut self.scene_manager.current_mut()); From 5f3da6ab99b7a3e8e86a440e212a1ee11910726e Mon Sep 17 00:00:00 2001 From: reo Date: Fri, 17 Oct 2025 23:18:18 +0300 Subject: [PATCH 5/5] Add FPS counter to the debug UI --- game/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/game/src/main.rs b/game/src/main.rs index 4e0ee6e..ad230cf 100644 --- a/game/src/main.rs +++ b/game/src/main.rs @@ -71,6 +71,7 @@ impl System for RenderingTestSystem { dbg_ui.text("Hello World!".to_owned()); dbg_ui.text(format!("Frame Delta: {}", pctx.time_ctx.frame_dt)); dbg_ui.text(format!("Fixed Delta: {}", pctx.time_ctx.fixed_dt)); + dbg_ui.text(format!("FPS: {}", 1.0 / pctx.time_ctx.frame_dt)); dbg_ui.slider_f32("Rotation Speed", -10.0, 10.0, self.rotation_speed.clone()); }