Giant refactor for a better event-driven architecture

This commit is contained in:
reo 2025-07-21 23:52:32 +03:00
parent 341d531db3
commit 88a21040cd
22 changed files with 936 additions and 67 deletions

View file

@ -2,3 +2,8 @@
name = "raidillon_core"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.98"
glam = "0.30.4"
hecs = "0.10.5"

View file

@ -0,0 +1,95 @@
use std::collections::HashMap;
// Forward declarations - these will be from other crates
pub trait Model {}
pub trait Material {}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct ModelId(pub usize);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct MaterialId(pub usize);
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct TextureHandle(pub usize);
pub struct AssetManager<M: Model + ?Sized, Mat: Material + ?Sized> {
models: Vec<Box<M>>,
materials: Vec<Box<Mat>>,
textures: HashMap<String, TextureHandle>,
model_cache: HashMap<String, ModelId>,
next_texture_id: usize,
}
impl<M: Model + ?Sized, Mat: Material + ?Sized> AssetManager<M, Mat> {
pub fn new() -> Self {
Self {
models: Vec::new(),
materials: Vec::new(),
textures: HashMap::new(),
model_cache: HashMap::new(),
next_texture_id: 0,
}
}
pub fn add_model(&mut self, model: Box<M>) -> ModelId {
let id = ModelId(self.models.len());
self.models.push(model);
id
}
pub fn cache_model(&mut self, path: String, model: Box<M>) -> ModelId {
if let Some(&cached_id) = self.model_cache.get(&path) {
return cached_id;
}
let model_id = self.add_model(model);
self.model_cache.insert(path, model_id);
model_id
}
pub fn get_model(&self, id: ModelId) -> Option<&M> {
self.models.get(id.0).map(|boxed| boxed.as_ref())
}
pub fn get_model_mut(&mut self, id: ModelId) -> Option<&mut M> {
self.models.get_mut(id.0).map(|boxed| boxed.as_mut())
}
pub fn add_material(&mut self, material: Box<Mat>) -> MaterialId {
let id = MaterialId(self.materials.len());
self.materials.push(material);
id
}
pub fn get_material(&self, id: MaterialId) -> Option<&Mat> {
self.materials.get(id.0).map(|boxed| boxed.as_ref())
}
pub fn add_texture(&mut self, name: String) -> TextureHandle {
if let Some(&handle) = self.textures.get(&name) {
return handle;
}
let handle = TextureHandle(self.next_texture_id);
self.next_texture_id += 1;
self.textures.insert(name, handle);
handle
}
pub fn get_texture_handle(&self, name: &str) -> Option<TextureHandle> {
self.textures.get(name).copied()
}
pub fn model_count(&self) -> usize {
self.models.len()
}
pub fn material_count(&self) -> usize {
self.materials.len()
}
pub fn clear_cache(&mut self) {
self.model_cache.clear();
}
}

View file

@ -0,0 +1,80 @@
use hecs::World;
use crate::{
Time, EventBus, GameEvent, SystemRegistry,
AssetManager, Model, Material, ModelId
};
pub struct Engine {
pub world: World,
pub systems: SystemRegistry,
pub assets: AssetManager<dyn Model, dyn Material>,
pub events: EventBus,
pub time: Time,
}
impl Engine {
pub fn new() -> Self {
let systems = SystemRegistry::new();
Self {
world: World::new(),
systems,
assets: AssetManager::new(),
events: EventBus::new(),
time: Time::new(),
}
}
pub fn add_system<S: crate::System + 'static>(&mut self, system: S) {
self.systems.add_system(system);
}
pub fn update(&mut self) {
self.time.tick();
let dt = self.time.delta_seconds();
// Update all systems
self.systems.update_all(&mut self.world, &self.assets, &mut self.events, dt);
// Process events
self.events.process();
}
pub fn handle_window_event(&mut self, event: &GameEvent) {
self.events.emit(event.clone());
self.systems.handle_event_for_all(event, &mut self.world);
}
pub fn load_model(&mut self, path: &str) -> anyhow::Result<ModelId> {
// This is a placeholder - in a real implementation, we'd need to
// coordinate with the render system to actually load the model
// For now, just return a dummy ID
Ok(ModelId(0))
}
pub fn spawn_entity_with_model(&mut self, model_id: ModelId) -> hecs::Entity {
// This would need proper Transform and ModelHandle types
// For now, return a placeholder entity
self.world.spawn(())
}
pub fn delta_time(&self) -> f32 {
self.time.delta_seconds()
}
pub fn emit_event(&mut self, event: GameEvent) {
self.events.emit(event);
}
pub fn world(&self) -> &World {
&self.world
}
pub fn world_mut(&mut self) -> &mut World {
&mut self.world
}
pub fn system_count(&self) -> usize {
self.systems.system_count()
}
}

View file

@ -0,0 +1,60 @@
use glam::Vec3;
use hecs::Entity;
#[derive(Debug, Clone)]
pub enum GameEvent {
InputAction(InputAction),
CameraMove { position: Vec3, front: Vec3 },
WindowResize { width: u32, height: u32 },
EntitySpawned(Entity),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum InputAction {
MoveForward,
MoveBackward,
MoveLeft,
MoveRight,
}
pub trait EventHandler {
fn handle(&mut self, event: &GameEvent);
}
pub struct EventBus {
events: Vec<GameEvent>,
handlers: Vec<Box<dyn EventHandler>>,
}
impl EventBus {
pub fn new() -> Self {
Self {
events: Vec::new(),
handlers: Vec::new(),
}
}
pub fn emit(&mut self, event: GameEvent) {
self.events.push(event);
}
pub fn subscribe<H: EventHandler + 'static>(&mut self, handler: H) {
self.handlers.push(Box::new(handler));
}
pub fn process(&mut self) {
for event in self.events.drain(..) {
for handler in &mut self.handlers {
handler.handle(&event);
}
}
}
pub fn has_events(&self) -> bool {
!self.events.is_empty()
}
pub fn events(&self) -> &[GameEvent] {
&self.events
}
}

View file

@ -1,3 +1,11 @@
pub mod time;
pub mod events;
pub mod assets;
pub mod systems;
pub mod engine;
pub use time::Time;
pub use events::{GameEvent, InputAction, EventHandler, EventBus};
pub use assets::{AssetManager, ModelId, MaterialId, TextureHandle, Model, Material};
pub use systems::{System, SystemRegistry};
pub use engine::Engine;

View file

@ -0,0 +1,45 @@
use hecs::World;
use crate::assets::{AssetManager, Model, Material};
use crate::events::{EventBus, GameEvent};
pub trait System {
fn update(&mut self, world: &mut World, resources: &AssetManager<dyn Model, dyn Material>, events: &mut EventBus, dt: f32);
fn handle_event(&mut self, event: &GameEvent, world: &mut World);
fn name(&self) -> &'static str;
}
pub struct SystemRegistry {
systems: Vec<Box<dyn System>>,
}
impl SystemRegistry {
pub fn new() -> Self {
Self {
systems: Vec::new(),
}
}
pub fn add_system<S: System + 'static>(&mut self, system: S) {
self.systems.push(Box::new(system));
}
pub fn update_all(&mut self, world: &mut World, resources: &AssetManager<dyn Model, dyn Material>, events: &mut EventBus, dt: f32) {
for system in &mut self.systems {
system.update(world, resources, events, dt);
}
}
pub fn handle_event_for_all(&mut self, event: &GameEvent, world: &mut World) {
for system in &mut self.systems {
system.handle_event(event, world);
}
}
pub fn system_count(&self) -> usize {
self.systems.len()
}
pub fn clear(&mut self) {
self.systems.clear();
}
}