diff --git a/crates/comet_ecs/src/scene.rs b/crates/comet_ecs/src/scene.rs index 7f3530e..bc0e23c 100755 --- a/crates/comet_ecs/src/scene.rs +++ b/crates/comet_ecs/src/scene.rs @@ -112,9 +112,7 @@ impl Scene { self.remove_entity_from_archetype(entity_id.index, self.get_component_set(idx)); self.entities[idx] = None; info!("Deleted entity! ID: {}", entity_id.index); - for (_, value) in self.components.iter_mut() { - value.remove::(idx); - } + self.components.remove_entity(idx); if let Some(gen) = self.generations.get_mut(idx) { *gen = gen.wrapping_add(1); } diff --git a/crates/comet_structs/src/column.rs b/crates/comet_structs/src/column.rs index 6e2eafc..6b8ee1a 100644 --- a/crates/comet_structs/src/column.rs +++ b/crates/comet_structs/src/column.rs @@ -272,6 +272,17 @@ impl Column { } } + /// Remove an element without knowing its concrete type. Drops in place. + pub fn remove_any(&mut self, index: usize) { + if index >= self.data.len() { + return; + } + unsafe { + let ptr = self.data.swap_remove_and_forget_unchecked(index); + (self.data.drop)(ptr); + } + } + /// Overwrites an existing element in place, dropping the previous value. pub fn set(&mut self, index: usize, item: T) -> Option<()> { assert_eq!(TypeId::of::(), TypeId::of::(), "Type mismatch"); diff --git a/crates/comet_structs/src/component_storage.rs b/crates/comet_structs/src/component_storage.rs index 3216bda..017a776 100644 --- a/crates/comet_structs/src/component_storage.rs +++ b/crates/comet_structs/src/component_storage.rs @@ -55,4 +55,11 @@ impl ComponentStorage { None } } + + /// Removes all components belonging to the given entity index. + pub fn remove_entity(&mut self, index: usize) { + for (_, value) in self.iter_mut() { + value.remove_any(index); + } + } } diff --git a/crates/comet_structs/src/sparse_set.rs b/crates/comet_structs/src/sparse_set.rs index 8000ba7..d5bbcb1 100644 --- a/crates/comet_structs/src/sparse_set.rs +++ b/crates/comet_structs/src/sparse_set.rs @@ -75,6 +75,64 @@ impl SparseSet { None } + /// Removes an element by external index without knowing its type. Returns true if something was removed. + pub fn remove_any(&mut self, index: usize) -> bool { + if let Some(page_vec) = self + .sparse + .get(index / self.page_size) + .and_then(|x| x.as_ref()) + { + if let Some(sparse_index) = page_vec + .get(index % self.page_size) + .and_then(|x| x.as_ref()) + { + let dense_index = *sparse_index; + let last_dense_index = self.dense.data.len() - 1; + + if dense_index != last_dense_index { + if let Some(ext_index) = self.find_external_index(last_dense_index) { + if let Some(page_vec) = self + .sparse + .get_mut(ext_index / self.page_size) + .and_then(|x| x.as_mut()) + { + page_vec[ext_index % self.page_size] = Some(dense_index); + } + } + self.dense.swap(dense_index, last_dense_index); + } + + if let Some(page_vec) = self + .sparse + .get_mut(index / self.page_size) + .and_then(|x| x.as_mut()) + { + page_vec[index % self.page_size] = None; + } + + self.dense.remove_any(dense_index); + return true; + } + } + false + } + + /// Finds the external index that maps to a given dense index. + fn find_external_index(&self, dense_index: usize) -> Option { + for (page_idx, page_opt) in self.sparse.iter().enumerate() { + if let Some(page) = page_opt { + for (offset, entry) in page.iter().enumerate() { + if let Some(idx) = entry { + if *idx == dense_index { + return Some(page_idx * self.page_size + offset); + } + } + } + } + } + None + } + pub fn get(&self, index: usize) -> Option<&T> { if let Some(page_vec) = self .sparse