From 01066718b0f13846587d26b1869f03e3713082c6 Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 12 Mar 2024 20:54:42 +0100 Subject: feat(ecs): make components internally mutable --- ecs/src/lib.rs | 160 +++++++++++++++++---------------------------------------- 1 file changed, 46 insertions(+), 114 deletions(-) (limited to 'ecs/src/lib.rs') diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 6b9373c..d781b3e 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -1,10 +1,11 @@ #![deny(clippy::all, clippy::pedantic)] use std::any::{Any, TypeId}; +use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::marker::PhantomData; -use std::slice::{Iter as SliceIter, IterMut as SliceIterMut}; +use std::slice::Iter as SliceIter; use crate::actions::Action; use crate::component::{Component, Sequence as ComponentSequence}; @@ -28,7 +29,7 @@ pub use ecs_macros::Component; #[derive(Debug, Default)] struct Entity { - components: Vec>, + components: Vec>>, } #[derive(Debug, Default)] @@ -50,18 +51,20 @@ impl World where Comps: ComponentSequence, { - self.data - .component_storage - .entities - .push(Entity { components: components.into_vec() }); + self.data.component_storage.entities.push(Entity { + components: components + .into_vec() + .into_iter() + .map(RefCell::new) + .collect(), + }); } - pub fn register_system( - &mut self, + pub fn register_system<'this, SystemImpl>( + &'this mut self, event: &impl Event, - system: TSystem, - ) where - TSystem: System, + system: impl System<'this, SystemImpl>, + ) { self.systems.push(system.into_type_erased()); @@ -77,36 +80,38 @@ impl World /// /// # Panics /// Will panic if a system has dissapeared. - pub fn emit(&mut self, event: &impl Event) + pub fn emit(&self, event: &impl Event) { let Some(system_indices) = self.data.events.get(&event.id()).cloned() else { return; }; for system_index in system_indices { - let system = self.systems.get_mut(system_index).unwrap(); + let system = self.systems.get(system_index).unwrap(); - system.run(&mut self.data); + // SAFETY: The world data lives long enough + unsafe { + system.run(&self.data); + } } } - pub fn query(&mut self) -> Query + pub fn query(&self) -> Query where Comps: ComponentSequence, { - Query::new(&mut self.data) + Query::new(&self.data) } /// Peforms the actions that have been queued up using [`Actions`]. pub fn perform_queued_actions(&mut self) { - for action in self.data.action_queue.drain(..) { + for action in self.data.action_queue.borrow_mut().drain(..) { match action { Action::Spawn(components) => { - self.data - .component_storage - .entities - .push(Entity { components }); + self.data.component_storage.entities.push(Entity { + components: components.into_iter().map(RefCell::new).collect(), + }); } } } @@ -118,7 +123,7 @@ pub struct WorldData { events: HashMap>, component_storage: ComponentStorage, - action_queue: Vec, + action_queue: RefCell>, } #[derive(Debug)] @@ -126,7 +131,7 @@ pub struct Query<'world, Comps> where Comps: ComponentSequence, { - world_data: &'world mut WorldData, + world_data: &'world WorldData, comps_pd: PhantomData, } @@ -134,17 +139,7 @@ impl<'world, Comps> Query<'world, Comps> where Comps: ComponentSequence, { - fn new(world_data: &'world mut WorldData) -> Self - { - Self { world_data, comps_pd: PhantomData } - } -} - -impl<'world, Comps> Query<'world, Comps> -where - Comps: ComponentSequence, -{ - pub fn iter(&self) -> QueryComponentIter + pub fn iter(&self) -> QueryComponentIter<'world, Comps> { QueryComponentIter { entity_iter: self.world_data.component_storage.entities.iter(), @@ -153,13 +148,9 @@ where } } - pub fn iter_mut(&mut self) -> QueryComponentMutIter + fn new(world_data: &'world WorldData) -> Self { - QueryComponentMutIter { - entity_iter: self.world_data.component_storage.entities.iter_mut(), - component_type_ids: Comps::type_ids(), - comps_pd: PhantomData, - } + Self { world_data, comps_pd: PhantomData } } } @@ -176,19 +167,6 @@ where } } -impl<'world, Comps> IntoIterator for &'world mut Query<'world, Comps> -where - Comps: ComponentSequence, -{ - type IntoIter = QueryComponentMutIter<'world, Comps>; - type Item = Comps::MutRefs<'world>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter_mut() - } -} - unsafe impl<'world, Comps> SystemParam<'world> for Query<'world, Comps> where Comps: ComponentSequence, @@ -196,13 +174,16 @@ where type Flags = NoInitSystemParamFlag; type Input = TupleFilterExclude; - fn initialize(_system: &mut impl System, _input: Self::Input) + fn initialize( + _system: &mut impl System<'world, SystemImpl>, + _input: Self::Input, + ) { } fn new( - _system: &'world mut impl System, - world_data: &'world mut WorldData, + _system: &'world impl System<'world, SystemImpl>, + world_data: &'world WorldData, ) -> Self { Self::new(world_data) @@ -268,75 +249,26 @@ where fn next(&mut self) -> Option { - let matching_entity = find_entity_with_components::<&Entity>( - &mut self.entity_iter, - &self.component_type_ids, - )?; + let matching_entity = + find_entity_with_components(&mut self.entity_iter, &self.component_type_ids)?; Some(Comps::from_components(&matching_entity.components)) } } -pub struct QueryComponentMutIter<'world, Comps> -{ - entity_iter: SliceIterMut<'world, Entity>, - component_type_ids: Vec, - comps_pd: PhantomData, -} - -impl<'world, Comps> Iterator for QueryComponentMutIter<'world, Comps> -where - Comps: ComponentSequence + 'world, -{ - type Item = Comps::MutRefs<'world>; - - fn next(&mut self) -> Option - { - let matching_entity = find_entity_with_components::<&mut Entity>( - &mut self.entity_iter, - &self.component_type_ids, - )?; - - Some(Comps::from_components_mut(&mut matching_entity.components)) - } -} - -trait EntityRef -{ - fn components(&self) -> &[Box]; -} - -impl EntityRef for &Entity -{ - fn components(&self) -> &[Box] - { - &self.components - } -} - -impl EntityRef for &mut Entity -{ - fn components(&self) -> &[Box] - { - &self.components - } -} - -fn find_entity_with_components( - entity_iter: &mut impl Iterator, +fn find_entity_with_components<'world>( + entity_iter: &mut impl Iterator, component_type_ids: &[TypeId], -) -> Option -where - EntityRefT: EntityRef, +) -> Option<&'world Entity> { // TODO: This is a really dumb and slow way to do this. Refactor the world // to store components in archetypes entity_iter.find(|entity| { - let entity_components: HashSet<_> = entity - .components() + let entity_components = entity + .components .iter() - .map(|component| component.as_ref().type_id()) - .collect(); + .filter_map(|component| Some(component.try_borrow().ok()?.as_ref().type_id())) + .collect::>(); if component_type_ids .iter() -- cgit v1.2.3-18-g5258