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".
This commit is contained in:
reo 2025-10-15 22:33:04 +03:00
parent 6e42d94b44
commit ef055a1bda
16 changed files with 287 additions and 93 deletions

View file

@ -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<RefCell<DebugUIBuffer>>;
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<RefCell<DebugUIBuffer>>);
// fn scene_and_debug_ui_buffer_mut(&mut self) -> (&mut Self::Scene, &DebugUIBuffer);
}

View file

@ -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::*;

View file

@ -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<PathBuf>,
pub resources: SceneResources,
}
define_typemap!(SceneResources,);
impl Scene {
pub fn new(title: String, skybox_texture_path: Option<PathBuf>) -> 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);
}
}

View file

@ -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<dyn $trait_name>>,
}
impl $manager_name {
pub fn new() -> Self {
Self {
systems: ::indexmap::IndexMap::default(),
}
}
pub fn add<S: $trait_name + Default + 'static>(&mut self) {
self.systems
.insert(::std::any::TypeId::of::<S>(), Box::new(S::default()));
}
pub fn remove<S: 'static>(&mut self) {
self.systems.shift_remove(&::std::any::TypeId::of::<S>());
}
pub fn for_each_value<F>(&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<F>(&mut self, mut f: F)
where
F: FnMut(&mut dyn $trait_name),
{
for value in self.systems.values_mut() {
f(value.as_mut());
}
}
}
};
}

2
core/src/utils/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod typemap;
mod managers;

122
core/src/utils/typemap.rs Normal file
View file

@ -0,0 +1,122 @@
#[macro_export]
macro_rules! define_typemap {
($name:ident, $($trait_bound:tt)*) => {
pub struct $name {
map: std::collections::HashMap<std::any::TypeId, Box<dyn std::any::Any>>,
}
impl $name {
pub fn new() -> Self {
Self {
map: std::collections::HashMap::new(),
}
}
pub fn insert<T>(&mut self, value: T) -> Option<Box<T>>
where
T: std::any::Any + 'static + $($trait_bound)*,
{
let type_id = std::any::TypeId::of::<T>();
self.map
.insert(type_id, Box::new(value))
.and_then(|boxed| boxed.downcast().ok())
}
pub fn get<T>(&self) -> Option<&T>
where
T: std::any::Any + 'static + $($trait_bound)*,
{
self.map
.get(&std::any::TypeId::of::<T>())
.and_then(|any| any.downcast_ref::<T>())
}
pub fn get_mut<T>(&mut self) -> Option<&mut T>
where
T: std::any::Any + 'static + $($trait_bound)*,
{
self.map
.get_mut(&std::any::TypeId::of::<T>())
.and_then(|any| any.downcast_mut::<T>())
}
pub fn remove<T>(&mut self) -> Option<Box<T>>
where
T: std::any::Any + 'static + $($trait_bound)*,
{
self.map
.remove(&std::any::TypeId::of::<T>())
.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<T>(&self) -> bool
where
T: std::any::Any + 'static + $($trait_bound)*,
{
self.map.contains_key(&std::any::TypeId::of::<T>())
}
}
impl Default for $name {
fn default() -> Self {
Self::new()
}
}
};
}
// pub struct TypeMap {
// map: HashMap<TypeId, Box<dyn Any>>,
// }
//
// impl TypeMap {
// pub fn new() -> Self {
// Self {
// map: HashMap::new(),
// }
// }
//
// pub fn insert<T: Any + 'static>(&mut self, value: T) -> Option<Box<T>> {
// let type_id = TypeId::of::<T>();
// self.map
// .insert(type_id, Box::new(value))
// .and_then(|boxed| boxed.downcast().ok())
// }
//
// pub fn get<T>(&self) -> Option<&T>
// where
// T: Any + 'static,
// {
// self.map.get(&TypeId::of::<T>())
// .and_then(|any| any.downcast_ref::<T>())
// }
//
// pub fn get_mut<T>(&mut self) -> Option<&mut T>
// where
// T: Any + 'static,
// {
// self.map.get_mut(&TypeId::of::<T>()).and_then(|any| any.downcast_mut::<T>())
// }
//
// pub fn remove<T: Any>(&mut self) -> Option<Box<T>> {
// unimplemented!()
// }
// }
//
// impl Default for TypeMap {
// fn default() -> Self {
// Self::new()
// }
// }