From db405bfb2e81bdcd59230c1caea9032725748022 Mon Sep 17 00:00:00 2001 From: lisk77 Date: Tue, 4 Mar 2025 23:52:16 +0100 Subject: [PATCH] wip: transitioning to the newer `comet_structs` and new `ComponentStorage` through a `FlatMap` (not the rust implementation) --- comet_structs/src/flat_map.rs | 64 -- comet_structs/src/lib.rs | 5 - comet_structs/src/sparse_set.rs | 91 --- crates/comet_ecs/src/archetypes.rs | 51 ++ crates/comet_ecs/src/component.rs | 4 +- crates/comet_ecs/src/lib.rs | 3 +- crates/comet_ecs/src/storage.rs | 591 ------------------ crates/comet_ecs/src/world.rs | 7 +- crates/comet_structs/src/component_storage.rs | 74 +++ crates/comet_structs/src/flat_map.rs | 105 ++-- crates/comet_structs/src/iter_mut.rs | 15 + crates/comet_structs/src/lib.rs | 6 +- 12 files changed, 214 insertions(+), 802 deletions(-) delete mode 100644 comet_structs/src/flat_map.rs delete mode 100644 comet_structs/src/lib.rs delete mode 100644 comet_structs/src/sparse_set.rs create mode 100644 crates/comet_ecs/src/archetypes.rs delete mode 100644 crates/comet_ecs/src/storage.rs create mode 100644 crates/comet_structs/src/component_storage.rs create mode 100644 crates/comet_structs/src/iter_mut.rs diff --git a/comet_structs/src/flat_map.rs b/comet_structs/src/flat_map.rs deleted file mode 100644 index 4b69170..0000000 --- a/comet_structs/src/flat_map.rs +++ /dev/null @@ -1,64 +0,0 @@ -pub struct MapNode { - key: K, - value: V -} - -impl MapNode { - pub fn new(key: K, value: V) -> Self { - Self { - key, - value - } - } - - pub fn key(&self) -> &K { - &self.key - } - - pub fn value(&self) -> &V { - &self.value - } -} - -pub struct FlatMap { - map: Vec -} - -impl FlatMap { - pub fn new() -> Self { - Self { - map: Vec::new() - } - } - - pub fn insert(key: K, value: V) { - let node = MapNode::new(key, value); - self.map.push(node); - } - - pub fn remove(key: K) { - for node in self.map { - if node.key() == key { - self.map.remove(node); - } - } - } - - pub fn get(key: K) -> Option<&V> { - for node in self.map { - if node.key() == key { - return Some(&node.value); - } - } - return None; - } - - pub fn get_mut(key: K) -> Option<&mut V> { - for node in self.map { - if node.key() == key { - return Some(&mut node.value); - } - } - return None; - } -} diff --git a/comet_structs/src/lib.rs b/comet_structs/src/lib.rs deleted file mode 100644 index 52f5f9c..0000000 --- a/comet_structs/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub use column::Column; -pub use sparse_set::SparseSet; - -mod column; -mod sparse_set; diff --git a/comet_structs/src/sparse_set.rs b/comet_structs/src/sparse_set.rs deleted file mode 100644 index 0771134..0000000 --- a/comet_structs/src/sparse_set.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::{Component}; -use std::{ - alloc::{ - handle_alloc_error, - Layout - }, - any::TypeId, - collections::{ - HashMap, - HashSet - }, - hash::{ - DefaultHasher, - Hash, - Hasher - }, - mem::MaybeUninit, - ptr::NonNull -}; -use std::ptr; - -#[derive(Debug, Clone)] -pub struct SparseSet { - sparse: Vec>, - dense: Column, - len: usize -} - -impl SparseSet { - pub fn new(capacity: usize) -> Self { - Self { - sparse: Vec::with_capacity(capacity), - dense: Column::new::(capacity), - len: 0 - } - } - - pub fn set(&mut self, index: usize, element: T) { - if index >= self.sparse.len() { - self.sparse.resize_with(index + 1, || None); - } - - if let Some(column_index) = self.sparse[index] { - // Explicitly drop the existing component before replacing it - unsafe { - let existing_ptr = self.dense.data.get_unchecked_mut(column_index) as *mut T; - ptr::drop_in_place(existing_ptr); - ptr::write(existing_ptr, element); - } - } else { - let column_index = unsafe { self.dense.data.push_uninit() }; - unsafe { - self.dense.data.initialize_unchecked(column_index, &element as *const T as *mut u8); - } - self.sparse[index] = Some(column_index); - self.len += 1; - } - } - - pub fn remove(&mut self, index: usize) -> Option { - if index >= self.sparse.len() || self.sparse[index] == None { - return None; - } - - let column_index = self.sparse[index]; - let element = unsafe { - self.dense.data.swap_remove_and_forget_unchecked(column_index.unwrap()) - }; - - self.sparse[index] = None; - self.len -= 1; - - Some(unsafe { ptr::read(element as *const T) }) - } - - pub fn get(&self, index: usize) -> Option<&T> { - if index >= self.sparse.len() || self.sparse[index] == None { - return None; - } - - self.dense.get::(index) - } - - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if index >= self.sparse.len() || self.sparse[index] == None { - return None; - } - - self.dense.get_mut::(index) - } -} diff --git a/crates/comet_ecs/src/archetypes.rs b/crates/comet_ecs/src/archetypes.rs new file mode 100644 index 0000000..b80709f --- /dev/null +++ b/crates/comet_ecs/src/archetypes.rs @@ -0,0 +1,51 @@ +use std::collections::HashMap; +use crate::ComponentSet; + +#[derive(Debug, Clone)] +pub struct Archetypes { + archetypes: HashMap> +} + +impl Archetypes { + pub fn new() -> Self { + Self { + archetypes: HashMap::new() + } + } + + pub fn component_sets(&self) -> Vec { + self.archetypes.keys().cloned().collect() + } + + pub fn create_archetype(&mut self, components: ComponentSet) { + self.archetypes.insert(components, Vec::new()); + } + + pub fn get_archetype(&self, components: &ComponentSet) -> Option<&Vec> { + self.archetypes.get(components) + } + + pub fn get_archetype_mut(&mut self, components: &ComponentSet) -> Option<&mut Vec> { + self.archetypes.get_mut(components) + } + + pub fn add_entity_to_archetype(&mut self, components: &ComponentSet, entity: u32) { + if let Some(archetype) = self.archetypes.get_mut(components) { + archetype.push(entity); + } + } + + pub fn remove_entity_from_archetype(&mut self, components: &ComponentSet, entity: u32) { + if let Some(archetype) = self.archetypes.get_mut(components) { + archetype.retain(|&id| id != entity); + } + } + + pub fn remove_archetype(&mut self, components: &ComponentSet) { + self.archetypes.remove(components); + } + + pub fn contains_archetype(&self, components: &ComponentSet) -> bool { + self.archetypes.contains_key(components) + } +} \ No newline at end of file diff --git a/crates/comet_ecs/src/component.rs b/crates/comet_ecs/src/component.rs index 7df8d10..f77b99b 100644 --- a/crates/comet_ecs/src/component.rs +++ b/crates/comet_ecs/src/component.rs @@ -298,7 +298,7 @@ impl Camera2D { self.dimensions = dimensions; } - fn in_view_frustum(&self, camera_pos: Position2D, entity: Position2D) -> bool { + pub fn in_view_frustum(&self, camera_pos: Position2D, entity: Position2D) -> bool { let left = camera_pos.x() - self.zoom; let right = camera_pos.x() + self.zoom; let bottom = camera_pos.y() - self.zoom; @@ -328,4 +328,4 @@ impl Camera for Camera2D { Mat4::OPENGL * Mat4::orthographic_matrix(left, right, bottom, top, 1.0, 0.0) } -} \ No newline at end of file +} diff --git a/crates/comet_ecs/src/lib.rs b/crates/comet_ecs/src/lib.rs index 46d1fdc..9e54715 100644 --- a/crates/comet_ecs/src/lib.rs +++ b/crates/comet_ecs/src/lib.rs @@ -10,4 +10,5 @@ mod storage; mod entity; mod component; mod world; -mod id; \ No newline at end of file +mod id; +mod archetypes; \ No newline at end of file diff --git a/crates/comet_ecs/src/storage.rs b/crates/comet_ecs/src/storage.rs deleted file mode 100644 index e056480..0000000 --- a/crates/comet_ecs/src/storage.rs +++ /dev/null @@ -1,591 +0,0 @@ -use crate::{Component}; -use std::{ - alloc::{ - handle_alloc_error, - Layout - }, - any::TypeId, - collections::{ - HashMap, - HashSet - }, - hash::{ - DefaultHasher, - Hash, - Hasher - }, - mem::MaybeUninit, - ptr::NonNull -}; -use std::ptr; - -#[derive(Debug, Clone)] -pub struct BlobVec { - item_layout: Layout, - capacity: usize, - len: usize, - data: NonNull, - swap_scratch: NonNull, - drop: unsafe fn(*mut u8) -} - - -impl BlobVec { - pub fn new(item_layout: Layout, drop: unsafe fn(*mut u8), capacity: usize) -> Self { - if item_layout.size() == 0 { - BlobVec { - swap_scratch: NonNull::dangling(), - data: NonNull::dangling(), - capacity: usize:: MAX, - len: 0, - item_layout, - drop, - } - } - else { - let swap_scratch = NonNull::new(unsafe { std::alloc::alloc(item_layout) }) - .unwrap_or_else(|| handle_alloc_error(item_layout)); - - let mut blob_vec = BlobVec { - swap_scratch, - data: NonNull::dangling(), - capacity: 0, - len: 0, - item_layout, - drop, - }; - blob_vec.reserve_exact(capacity); - blob_vec - } - } - - pub fn reserve_exact(&mut self, additional: usize) { - let available_space = self.capacity - self.len; - if available_space < additional { - self.grow_exact(additional - available_space); - } - } - - fn grow_exact(&mut self, increment: usize) { - debug_assert!(self.item_layout.size() != 0); - - let new_capacity = self.capacity + increment; - let new_layout = - array_layout(&self.item_layout, new_capacity).expect("array layout should be valid"); - unsafe { - let new_data = if self.capacity == 0 { - std::alloc::alloc(new_layout) - } else { - std::alloc::realloc( - self.get_ptr().as_ptr(), - array_layout(&self.item_layout, self.capacity) - .expect("array layout should be valid"), - new_layout.size(), - ) - }; - - self.data = NonNull::new(new_data).unwrap_or_else(|| handle_alloc_error(new_layout)); - } - self.capacity = new_capacity; - } - - - #[inline] - pub fn len(&self) -> usize { - self.len - } - - #[inline] - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - #[inline] - pub fn capacity(&self) -> usize { - self.capacity - } - - - #[inline] - pub unsafe fn get_ptr(&self) -> NonNull { - self.data - } - - #[inline] - pub unsafe fn push_uninit(&mut self) -> usize { - self.reserve_exact(1); - let index = self.len; - self.len += 1; - index - } - - #[inline] - pub unsafe fn get_unchecked(&self, index: usize) -> *mut u8 { - debug_assert!(index < self.len()); - self.get_ptr().as_ptr().add(index * self.item_layout.size()) - } - - #[inline] - pub unsafe fn get_unchecked_mut(&mut self, index: usize) -> *mut u8 { - debug_assert!(index < self.len()); - self.get_ptr().as_ptr().add(index * self.item_layout.size()) - } - - pub unsafe fn push_element(&mut self, element: T) { - let index = self.push_uninit(); - let ptr = self.get_unchecked(index) as *mut T; - ptr::write(ptr,element); - } - - pub fn clear(&mut self) { - let len = self.len; - // We set len to 0 _before_ dropping elements for unwind safety. This ensures we don't - // accidentally drop elements twice in the event of a drop impl panicking. - self.len = 0; - for i in 0..len { - unsafe { - // NOTE: this doesn't use self.get_unchecked(i) because the debug_assert on index - // will panic here due to self.len being set to 0 - let ptr = self.get_ptr().as_ptr().add(i * self.item_layout.size()); - (self.drop)(ptr); - } - } - } - - #[inline] - pub unsafe fn swap_remove_and_forget_unchecked(&mut self, index: usize) -> *mut u8 { - debug_assert!(index < self.len()); - let last = self.len - 1; - let swap_scratch = self.swap_scratch.as_ptr(); - ptr::copy_nonoverlapping( - self.get_unchecked(index), - swap_scratch, - self.item_layout.size(), - ); - ptr::copy( - self.get_unchecked(last), - self.get_unchecked(index), - self.item_layout.size(), - ); - self.len -= 1; - swap_scratch - } - - #[inline] - pub unsafe fn initialize_unchecked(&mut self, index: usize, value: *mut u8) { - debug_assert!(index < self.len()); - let ptr = self.get_unchecked(index); - ptr::copy_nonoverlapping(value, ptr, self.item_layout.size()); - } -} - -impl Drop for BlobVec { - fn drop(&mut self) { - self.clear(); - let array_layout = - array_layout(&self.item_layout, self.capacity).expect("array layout should be valid"); - if array_layout.size() > 0 { - unsafe { - std::alloc::dealloc(self.get_ptr().as_ptr(), array_layout); - std::alloc::dealloc(self.swap_scratch.as_ptr(), self.item_layout); - } - } - } -} - -unsafe impl Send for BlobVec {} -unsafe impl Sync for BlobVec {} - -fn array_layout(layout: &Layout, n: usize) -> Option { - let (array_layout, offset) = repeat_layout(layout, n)?; - debug_assert_eq!(layout.size(), offset); - Some(array_layout) -} - -fn repeat_layout(layout: &Layout, n: usize) -> Option<(Layout, usize)> { - let padded_size = layout.size() + padding_needed_for(layout, layout.align()); - let alloc_size = padded_size.checked_mul(n)?; - - unsafe { - Some(( - Layout::from_size_align_unchecked(alloc_size, layout.align()), - padded_size, - )) - } -} - -const fn padding_needed_for(layout: &Layout, align: usize) -> usize { - let len = layout.size(); - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); - len_rounded_up.wrapping_sub(len) -} - -#[derive(Debug, Clone)] -pub struct Column { - pub data: BlobVec -} - -impl Column { - pub fn new(capacity: usize) -> Self { - let layout = Layout::new::(); - let drop_fn = |ptr: *mut u8| unsafe { - ptr::drop_in_place(ptr as *mut T); - }; - Self { - data: BlobVec::new(layout, drop_fn, capacity), - } - } - - pub fn data(&self) -> BlobVec { - self.data.clone() - } - - pub fn push(&mut self, item: T) { - assert_eq!(TypeId::of::(), TypeId::of::(), "Type mismatch"); - unsafe { - let index = self.data.push_uninit(); - let ptr = self.data.get_unchecked(index); - ptr::write(ptr as *mut T, item); - } - } - - pub fn get(&self, index: usize) -> Option<&T> { - assert_eq!(TypeId::of::(), TypeId::of::(), "Type mismatch"); - if index >= self.data.len() { - return None; - } - unsafe { - let ptr = self.data.get_unchecked(index); - Some(&*(ptr as *const T)) - } - } - - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - assert_eq!(TypeId::of::(), TypeId::of::(), "Type mismatch"); - - if index >= self.data.len() { - return None; - } - - // Access the element at the given index - unsafe { - let ptr = self.data.get_unchecked(index); - // Convert the pointer to a mutable reference and return it - Some(&mut *(ptr as *mut T)) - } - } - - pub fn remove(&mut self, index: usize) -> Option { - assert_eq!(TypeId::of::(), TypeId::of::(), "Type mismatch"); - if index >= self.data.len() { - return None; - } - unsafe { - let ptr = self.data.swap_remove_and_forget_unchecked(index); - Some(ptr::read(ptr as *const T)) - } - } - - fn swap(&mut self, index1: usize, index2: usize) { - assert!(index1 < self.data.len() && index2 < self.data.len(), "Index out of bounds"); - - unsafe { - let ptr1 = self.data.get_unchecked(index1); - let ptr2 = self.data.get_unchecked(index2); - - let mut temp = MaybeUninit::::uninit(); - - // Swap the elements at index1 and index2 - ptr::copy_nonoverlapping(ptr1, temp.as_mut_ptr(), self.data.item_layout.size()); - ptr::copy_nonoverlapping(ptr2, ptr1, self.data.item_layout.size()); - ptr::copy_nonoverlapping(temp.as_ptr(), ptr2, self.data.item_layout.size()); - } - } -} - -pub struct IterMut<'a, K, V> { - keys_iter: std::slice::IterMut<'a, K>, - values_iter: std::slice::IterMut<'a, V>, -} - -impl<'a, K, V> Iterator for IterMut<'a, K, V> { - type Item = (&'a mut K, &'a mut V); - - fn next(&mut self) -> Option { - match (self.keys_iter.next(), self.values_iter.next()) { - (Some(key), Some(value)) => Some((key, value)), - _ => None, - } - } -} - -#[derive(Debug, Clone)] -pub struct SparseSet { - sparse: Vec>, - dense: Column, - len: usize -} - -impl SparseSet { - pub fn new(capacity: usize) -> Self { - Self { - sparse: Vec::with_capacity(capacity), - dense: Column::new::(capacity), - len: 0 - } - } - - pub fn set(&mut self, index: usize, element: T) { - if index >= self.sparse.len() { - self.sparse.resize_with(index + 1, || None); - } - - if let Some(column_index) = self.sparse[index] { - // Explicitly drop the existing component before replacing it - unsafe { - let existing_ptr = self.dense.data.get_unchecked_mut(column_index) as *mut T; - ptr::drop_in_place(existing_ptr); - ptr::write(existing_ptr, element); - } - } else { - let column_index = unsafe { self.dense.data.push_uninit() }; - unsafe { - self.dense.data.initialize_unchecked(column_index, &element as *const T as *mut u8); - } - self.sparse[index] = Some(column_index); - self.len += 1; - } - } - - pub fn remove(&mut self, index: usize) -> Option { - if index >= self.sparse.len() || self.sparse[index] == None { - return None; - } - - let column_index = self.sparse[index]; - let element = unsafe { - self.dense.data.swap_remove_and_forget_unchecked(column_index.unwrap()) - }; - - self.sparse[index] = None; - self.len -= 1; - - Some(unsafe { ptr::read(element as *const T) }) - } - - pub fn get(&self, index: usize) -> Option<&T> { - if index >= self.sparse.len() || self.sparse[index] == None { - return None; - } - - self.dense.get::(index) - } - - pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { - if index >= self.sparse.len() || self.sparse[index] == None { - return None; - } - - self.dense.get_mut::(index) - } -} - -#[derive(Debug, Clone)] -pub struct ComponentStorage { - index_map: HashMap, - pub(crate) keys: Vec, - components: Vec -} - -impl ComponentStorage { - pub fn new() -> Self { - Self { - index_map: HashMap::new(), - keys: Vec::new(), - components: Vec::new() - } - } - - pub fn keys(&self) -> &Vec { - &self.keys - } - - pub fn contains_component(&self, type_id: &TypeId) -> bool { - self.keys.contains(type_id) - } - - pub fn contains_components(&self, component_set: ComponentSet) -> bool { - let mut contains = true; - for type_id in component_set.set.iter() { - if !self.keys.contains(type_id) { - contains = false; - break; - } - } - contains - } - - pub fn get(&self) -> Option<&SparseSet> { - self.components.get(*self.index_map.get(&T::type_id()).unwrap()) - } - - pub fn set(&mut self, sparse_set: SparseSet) { - let _ = self.components.get_mut(*self.index_map.get(&T::type_id()).unwrap()); - } - - pub fn register_component(&mut self, capacity: usize) { - //self.storage.insert(T::type_id(), SparseSet::new::(capacity)); - assert!(!self.keys.contains(&T::type_id()), "This component ({}) is already registered!", T::type_name()); - self.keys.push(T::type_id()); - self.index_map.insert(T::type_id(), self.keys.len()-1); - self.components.push(SparseSet::new::(capacity)); - } - - pub fn get_component(&self, entity_id: usize) -> Option<&T> { - //self.storage.get(&T::type_id()).unwrap().get::(*entity.id() as usize) - self.components.get(*self.index_map.get(&T::type_id()).unwrap()).unwrap().get::(entity_id) - } - - pub fn get_component_mut(&mut self, entity_id: usize) -> Option<&mut T> { - self.components.get_mut(*self.index_map.get(&T::type_id()).unwrap()).unwrap().get_mut::(entity_id) - } - - pub fn set_component(&mut self, entity_id: usize, component: T) { - let index = *self.index_map.get(&T::type_id()).unwrap(); - let sparse_set = self.components.get_mut(index).unwrap(); - - // Check if a component already exists for this entity - if let Some(existing_component) = sparse_set.get_mut::(entity_id) { - // Explicitly drop the existing component before overwriting it - std::mem::drop(existing_component); - } - - // Set the new component - sparse_set.set(entity_id, component); - } - - pub fn deregister_component(&mut self) { - let type_id = T::type_id(); - if let Some(&index) = self.index_map.get(&type_id) { - // Before removing the SparseSet, ensure all elements are properly dropped - let sparse_set = self.components.get_mut(index).unwrap(); - for i in 0..sparse_set.sparse.len() { - if sparse_set.sparse[i].is_some() { - sparse_set.remove::(i); - } - } - - self.components.remove(index); - self.index_map.remove(&type_id); - self.keys.retain(|&k| k != type_id); - } - } - - pub fn remove_component(&mut self, entity_id: usize) { - if let Some(index) = self.index_map.get(&T::type_id()) { - let sparse_set = self.components.get_mut(*index).unwrap(); - sparse_set.remove::(entity_id); - } - } - - pub(crate) fn get_dense_list_as_vec(&self) -> Option> { - let mut resulting_vec: Vec = Vec::new(); - - if let Some(sparse_set) = self.components.get(*self.index_map.get(&T::type_id()).unwrap()) { - for i in 0..sparse_set.dense.data.len() { - let item: T = sparse_set.dense.get::(i)?.clone(); - resulting_vec.push(item); - } - Some(resulting_vec) - } else { - None - } - } - - pub fn iter_mut(&mut self) -> IterMut<'_, TypeId, SparseSet> { - IterMut { - keys_iter: self.keys.iter_mut(), - values_iter: self.components.iter_mut(), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ComponentSet { - set: HashSet -} - -impl ComponentSet { - pub fn new() -> Self { - Self { - set: HashSet::new() - } - } - - pub fn from_ids(ids: Vec) -> Self { - Self { - set: ids.into_iter().collect() - } - } - - pub fn is_subset(&self, other: &ComponentSet) -> bool { - self.set.is_subset(&other.set) - } -} - -impl Hash for ComponentSet { - fn hash(&self, state: &mut H) { - let mut types: Vec = self.set.iter().cloned().collect(); - types.sort(); - types.hash(state); - } -} - -#[derive(Debug, Clone)] -pub struct Archetypes { - archetypes: HashMap> -} - -impl Archetypes { - pub fn new() -> Self { - Self { - archetypes: HashMap::new() - } - } - - pub fn component_sets(&self) -> Vec { - self.archetypes.keys().cloned().collect() - } - - pub fn create_archetype(&mut self, components: ComponentSet) { - self.archetypes.insert(components, Vec::new()); - } - - pub fn get_archetype(&self, components: &ComponentSet) -> Option<&Vec> { - self.archetypes.get(components) - } - - pub fn get_archetype_mut(&mut self, components: &ComponentSet) -> Option<&mut Vec> { - self.archetypes.get_mut(components) - } - - pub fn add_entity_to_archetype(&mut self, components: &ComponentSet, entity: u32) { - if let Some(archetype) = self.archetypes.get_mut(components) { - archetype.push(entity); - } - } - - pub fn remove_entity_from_archetype(&mut self, components: &ComponentSet, entity: u32) { - if let Some(archetype) = self.archetypes.get_mut(components) { - archetype.retain(|&id| id != entity); - } - } - - pub fn remove_archetype(&mut self, components: &ComponentSet) { - self.archetypes.remove(components); - } - - pub fn contains_archetype(&self, components: &ComponentSet) -> bool { - self.archetypes.contains_key(components) - } -} diff --git a/crates/comet_ecs/src/world.rs b/crates/comet_ecs/src/world.rs index 7ac7e1e..35c0a0c 100644 --- a/crates/comet_ecs/src/world.rs +++ b/crates/comet_ecs/src/world.rs @@ -5,13 +5,12 @@ use crate::{ Component, Transform2D, Transform3D, - ComponentStorage, - SparseSet, IdQueue, Archetypes, ComponentSet }; use comet_log::*; +use comet_structs::*; #[derive(Clone)] pub struct World { @@ -144,7 +143,7 @@ impl World { fn get_component_set(&self, entity_id: usize) -> ComponentSet { let components = self.entities.get(entity_id).unwrap().as_ref().unwrap().get_components().iter().collect::>(); - let type_ids = components.iter().map(|index| self.components.keys[*index]).collect::>(); + let type_ids = components.iter().map(|index| self.components.keys()[*index]).collect::>(); ComponentSet::from_ids(type_ids) } @@ -165,7 +164,7 @@ impl World { pub fn add_component(&mut self, entity_id: usize, component: C) { assert_ne!(self.entities.get(entity_id), None, "There is no entity with this ID ({}) in the world!", entity_id); self.components.set_component(entity_id, component); - let component_index = self.components.keys.iter_mut().position(|x| *x == C::type_id()).unwrap(); + let component_index = self.components.keys().iter_mut().position(|x| *x == *C::type_id()).unwrap(); self.get_entity_mut(entity_id).unwrap().add_component(component_index); diff --git a/crates/comet_structs/src/component_storage.rs b/crates/comet_structs/src/component_storage.rs new file mode 100644 index 0000000..bf08d9a --- /dev/null +++ b/crates/comet_structs/src/component_storage.rs @@ -0,0 +1,74 @@ +use std::any::{Any, TypeId}; +use comet_log::*; +use crate::{FlatMap, IterMut, SparseSet}; + +pub type ComponentStorage = FlatMap; + +impl ComponentStorage { + + pub fn register_component(&mut self, capacity: usize) { + if !self.contains(&TypeId::of::()) { + self.insert(TypeId::of::(), SparseSet::new::(capacity)); + info!("Component {:?} has been registered", TypeId::of::()); + } + else { + error!("Component {:?} already exists", TypeId::of::()); + } + } + + pub fn deregister_component(&mut self) { + if self.contains(&TypeId::of::()) { + self.remove(&TypeId::of::()); + info!("Component {:?} has been deregistered", TypeId::of::()); + } + else { + error!("Component {:?} does not exist", TypeId::of::()); + } + } + + pub fn set_component(&mut self, index: usize, element: T) { + if let Some(sparse_set) = self.get_mut(&TypeId::of::()) { + sparse_set.set(index, element); + } + else { + error!("Component {:?} is not registered", TypeId::of::()); + } + } + + pub fn remove_component(&mut self, index: usize) -> Option { + if let Some(sparse_set) = self.get_mut(&TypeId::of::()) { + sparse_set.remove(index) + } + else { + error!("Component {:?} is not registered", TypeId::of::()); + None + } + } + + pub fn get_component(&self, index: usize) -> Option<&T> { + if let Some(sparse_set) = self.get(&TypeId::of::()) { + sparse_set.get(index) + } + else { + error!("Component {:?} is not registered", TypeId::of::()); + None + } + } + + pub fn get_component_mut(&mut self, index: usize) -> Option<&mut T> { + if let Some(sparse_set) = self.get_mut(&TypeId::of::()) { + sparse_set.get_mut(index) + } + else { + error!("Component {:?} is not registered", TypeId::of::()); + None + } + } + + pub fn iter_mut(&mut self) -> IterMut<'_, &TypeId, &SparseSet> { + IterMut { + keys_iter: self.keys_mut(), + values_iter: self.values_mut(), + } + } +} \ No newline at end of file diff --git a/crates/comet_structs/src/flat_map.rs b/crates/comet_structs/src/flat_map.rs index 27b5927..ff0ab00 100644 --- a/crates/comet_structs/src/flat_map.rs +++ b/crates/comet_structs/src/flat_map.rs @@ -1,64 +1,83 @@ +#[derive(Clone)] pub struct MapNode { - key: K, - value: V + key: K, + value: V } impl MapNode { - pub fn new(key: K, value: V) -> Self { - Self { - key, - value + pub fn new(key: K, value: V) -> Self { + Self { + key, + value + } } - } - pub fn key(&self) -> &K { - &self.key - } + pub fn key(&self) -> &K { + &self.key + } - pub fn value(&self) -> &V { - &self.value - } + pub fn value(&self) -> &V { + &self.value + } } +#[derive(Clone)] pub struct FlatMap { - map: Vec> + map: Vec> } impl FlatMap { - pub fn new() -> Self { - Self { - map: Vec::new() + pub fn new() -> Self { + Self { + map: Vec::new() + } } - } - pub fn insert(&mut self, key: K, value: V) { - let node = MapNode::new(key, value); - self.map.push(node); - } - - pub fn remove(&mut self, key: K) { - for node in self.map { - if node.key() == *key { - self.map.retain(|&n| n.key() != *key); - } + pub fn keys(&self) -> Vec<&K> { + self.map.iter().map(|node| node.key()).collect::>() } - } - pub fn get(&self, key: K) -> Option<&V> { - for node in self.map { - if node.key() == *key { - return Some(&node.value); - } + pub fn values(&self) -> Vec<&V> { + self.map.iter().map(|node| node.value()).collect::>() } - None - } - pub fn get_mut(&mut self, key: K) -> Option<&mut V> { - for mut node in self.map { - if node.key() == *key { - return Some(node.value); - } + pub fn keys_mut(&mut self) -> impl Iterator { + self.map.iter_mut().map(|node| &mut node.key) + } + + pub fn values_mut(&mut self) -> impl Iterator { + self.map.iter_mut().map(|node| &mut node.value) + } + + pub fn insert(&mut self, key: K, value: V) { + let node = MapNode::new(key, value); + self.map.push(node); + } + + pub fn remove(&mut self, key: &K) { + self.map.retain(|node| node.key() != key); + } + + pub fn get(&self, key: &K) -> Option<&V> { + self.map.iter() + .find(|node| node.key() == key) + .map(|node| node.value()) + } + + pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { + self.map.iter_mut() + .find(|node| node.key() == key) + .map(|node| node.value_mut()) + } + + pub fn contains(&self, key: &K) -> bool { + self.map.iter().any(|node| node.key() == key) } - None - } } + +// Add this method to MapNode to allow mutable access to value +impl MapNode { + fn value_mut(&mut self) -> &mut V { + &mut self.value + } +} \ No newline at end of file diff --git a/crates/comet_structs/src/iter_mut.rs b/crates/comet_structs/src/iter_mut.rs new file mode 100644 index 0000000..59e2d5f --- /dev/null +++ b/crates/comet_structs/src/iter_mut.rs @@ -0,0 +1,15 @@ +pub struct IterMut<'a, K, V> { + pub(crate) keys_iter: std::slice::IterMut<'a, K>, + pub(crate) values_iter: std::slice::IterMut<'a, V>, +} + +impl<'a, K, V> Iterator for IterMut<'a, K, V> { + type Item = (&'a mut K, &'a mut V); + + fn next(&mut self) -> Option { + match (self.keys_iter.next(), self.values_iter.next()) { + (Some(key), Some(value)) => Some((key, value)), + _ => None, + } + } +} \ No newline at end of file diff --git a/crates/comet_structs/src/lib.rs b/crates/comet_structs/src/lib.rs index ddf9d17..d96a1bd 100644 --- a/crates/comet_structs/src/lib.rs +++ b/crates/comet_structs/src/lib.rs @@ -1,7 +1,11 @@ pub use column::Column; pub use sparse_set::SparseSet; pub use flat_map::FlatMap; +pub use component_storage::ComponentStorage; +pub use iter_mut::IterMut; mod column; mod sparse_set; -mod flat_map; \ No newline at end of file +mod flat_map; +mod component_storage; +mod iter_mut; \ No newline at end of file